2015-10-28 21 views
9

Trong khi chơi với các mẫu variadic, các lớp học, chức năng và lambdas, (from here) tôi thấy rằng đoạn mã sau đang chạy với clang++ khi không chạy với g++:variadic mẫu sử dụng lambdas: lỗi với g ++ nhưng chạy với kêu vang ++

#include <iostream> 
#include <string> 
using namespace std; 
template <class... F> 
struct overload_set : F... 
{ 
    overload_set(F... f) : F(f)... {} 
}; 
template <class... F> 
auto overload(F... f) 
{ 
    return overload_set<F...>(f...); 
} 
int main() 
{ 
    auto func = overload (
     [](int &val) { val *= 2; }, 
     [](string &arg) { arg += arg; }, 
     [](char &c) { c = 'x'; } 
     ); 
    int val = 10; 
    string str = "stackoverflow"; 
    char ch = 's'; 
    cout << val << " : " << str << " : " << ch << endl; 
    func(val); 
    func(str); 
    func(ch); 
    cout << val << " : " << str << " : " << ch << endl; 
    return 0; 
} 

Đối clang: coliru

Đối g++: coliru

g++ đang đưa ra mơ hồ operator() cho func(val), func(str)func(c). Tôi nghĩ rằng operator() không được mơ hồ, vì mỗi loại có các đối số khác nhau.

Sự cố với g++ là gì?

+1

@Niall: nó không thực sự về lambdas hoặc thậm chí các mẫu variadic; ngay cả khi 'struct' đơn giản nhất xuất phát từ các cơ sở' B1', 'B2' ... với các hàm' operator() (X &) 'khác, g ++ cần' sử dụng toán tử B1 ::(); sử dụng toán tử B2 ::(); '(xem [ở đây] (http://coliru.stacked-crooked.com/a/8bc933418b5ff82f)). –

+1

@TonyD. Tôi nghĩ rằng nó là một lỗi clang - một số thử nghiệm cho thấy có một sự khác biệt ở đây trong cách clang giải quyết các chức năng từ các lớp cơ sở so với cách nó giải quyết toán tử cuộc gọi. – Niall

+0

@Niall gotcha, clang giải quyết 'x()' khác với 'x.operator()()'. –

Trả lời

3

Điều này ít liên quan đến lambdas, các mẫu biến thể, toán tử hoặc bất kỳ công cụ C++ 1 {xy} nâng cao nào. Hãy đơn giản hóa:

struct foo 
{ 
    void func(int&){} 
}; 
struct bar 
{ 
    void func(char&){} 
}; 

struct test : foo, bar {}; 

int main() 
{ 
    test t; 
    int i = 1; 
    char c = 'a'; 
    t.func(i); 
    t.func(c); 
} 

Điều này không thể biên dịch trong số g++ hoặc clang++. Đó là một điều tốt, bởi vì đó là cách ngôn ngữ được chỉ định để làm việc.

Nếu chúng ta thay đổi func-operator(), g++ tiếp tục từ chối chương trình nhưng clang++ hoặc chấp nhận hoặc từ chối yêu cầu, tùy thuộc vào cách điều hành được gọi là:

t.operator()(c); // rejected 
t(c);   // accepted 

nào trông giống như một lỗi kêu vang với tôi.

Để thực hiện đoạn mã trên biên dịch, một thay đổi rất nhỏ là cần thiết:

struct test : foo, bar { 
    using foo::func; 
    using bar::func; 
}; 

Bây giờ tôi không có ý tưởng làm thế nào để làm cho công việc mở rộng gói trong chỉ thị sử dụng, hoặc nếu nó thực sự có thể. Nhưng có một cách giải quyết:

template <class... F> struct overload_set; 

template <> struct overload_set<> {}; 

template <class F> struct overload_set<F> : F { 
    using F::operator(); 
    overload_set(F f) : F(f) {} 
}; 

template <class F, class... Fs> 
struct overload_set<F, Fs...> : F, overload_set<Fs...> 
{ 
    overload_set(F f, Fs... fs) : F(f), overload_set<Fs...>(fs...) {} 
    using F::operator(); 
    using overload_set<Fs...>::operator(); 
}; 

Với điều này thay đổi mã của bạn biên dịch với cả g++clang++.

+2

Có một liên kết từ bài đăng trên blog được liên kết của OP đó là khá nhiều cách giải quyết này. Blog đề cập đến nó như là một "phiên bản sức mạnh công nghiệp", [liên kết tại đây] (https://github.com/picanumber/CODEine/blob/master/lambda_utils.h) – Niall

+0

@Niall Phiên bản công nghiệp là phiên bản tôi đã thấy Yakk trong số những người khác sử dụng (có các biến thể trên mẫu cơ sở, số lượng chuyên môn và việc sử dụng chuyển tiếp hoàn hảo) –

Các vấn đề liên quan