C ++中的重载lambdas和clang和gcc之间的区别 [英] Overloaded lambdas in C++ and differences between clang and gcc
问题描述
我正在玩一个技巧来重载C ++中的lambdas。具体来说:
// for std :: function
#include< functional&
//对于std :: string
#include< string>
//对于std :: cout
#include< iostream>
template< class ... F>
struct overload:F ... {
overload(F ... f):F(f)... {}
};
template< class ... F>
auto make_overload(F ... f){
return overload< F ...>(f ...);
}
int main(){
std :: function< int(int,int)> f = [](int x,int y){
return x + y;
};
std :: function< double(double,double)> g = [](double x,double y){
return x + y;
};
std :: function< std :: string(std :: string,std :: string)> h = [](std :: string x,std :: string y){
return x + y;
};
auto fgh = make_overload(f,g,h);
std :: cout<< fgh(1,2) std :: endl;
std :: cout<< fgh(1.5,2.5) std :: endl;
std :: cout<< fgh(bob,larry)<< std :: endl;
}
现在,上面的程序在clang中编译和工作:
$ clang ++ -g -std = c ++ 14 test01.cpp -o test01
$ ./test01
3
4
boblarry
它不能在gcc中编译:
$ g ++ -g -std = c ++ 14 test01.cpp -o test01
pre>
test01.cpp:在函数'int main ()':
test01.cpp:36:25:error:对成员'operator()'的请求是不明确的
std :: cout< fgh(1,2) std :: endl;
^
在test01.cpp中包含的文件中:5:0:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/功能:2434:5:注意:候选是:_Res std :: function< _Res(_ArgTypes ...)> :: operator()(_ArgTypes ...)const [with _Res = std :: basic_string< char& _ArgTypes = {std :: basic_string< char,std :: char_traits< char>,std :: allocator< char> >,std :: basic_string< char,std :: char_traits< char>,std :: allocator< char> >}]
function< _Res(_ArgTypes ...)> ::
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include / g ++ - v4 / functional:2434:5:note:_Res std :: function< _Res(_ArgTypes ...)> :: operator()(_ArgTypes ...)const [with _Res = double; _ArgTypes = {double,double}]
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5:note:_Res std :: function< ; _Res(_ArgTypes ...)> :: operator()(_ArgTypes ...)const [with _Res = int; _ArgTypes = {int,int}]
test01.cpp:37:29:error:对成员'operator()'的请求是不明确的
std :: cout< fgh(1.5,2.5) std :: endl;
^
在test01.cpp中包含的文件中:5:0:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/功能:2434:5:注意:候选是:_Res std :: function< _Res(_ArgTypes ...)> :: operator()(_ArgTypes ...)const [with _Res = std :: basic_string< char& _ArgTypes = {std :: basic_string< char,std :: char_traits< char>,std :: allocator< char> >,std :: basic_string< char,std :: char_traits< char>,std :: allocator< char> >}]
function< _Res(_ArgTypes ...)> ::
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include / g ++ - v4 / functional:2434:5:note:_Res std :: function< _Res(_ArgTypes ...)> :: operator()(_ArgTypes ...)const [with _Res = double; _ArgTypes = {double,double}]
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5:note:_Res std :: function< ; _Res(_ArgTypes ...)> :: operator()(_ ArgTypes ...)const [with _Res = int; _ArgTypes = {int,int}]
test01.cpp:38:35:error:member'operator()'的请求是不明确的
std :: cout< fgh(bob,larry)<< std :: endl;
^
在test01.cpp中包含的文件中:5:0:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/功能:2434:5:注意:候选是:_Res std :: function< _Res(_ArgTypes ...)> :: operator()(_ArgTypes ...)const [with _Res = std :: basic_string< char& _ArgTypes = {std :: basic_string< char,std :: char_traits< char>,std :: allocator< char> >,std :: basic_string< char,std :: char_traits< char>,std :: allocator< char> >}]
function< _Res(_ArgTypes ...)> ::
^
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include / g ++ - v4 / functional:2434:5:note:_Res std :: function< _Res(_ArgTypes ...)> :: operator()(_ArgTypes ...)const [with _Res = double; _ArgTypes = {double,double}]
/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5:note:_Res std :: function< ; _Res(_ArgTypes ...)> :: operator()(_ ArgTypes ...)const [with _Res = int; _ArgTypes = {int,int}]
Makefile:2:目标'all'失败的配方
make:*** [all]错误1
为什么有区别?对于记录,我使用gcc 4.9.2和clang 3.5.0。
编辑1
显然,这段代码在VC上编译失败,并且已经报告。也就是说,Sean Middleditch发布了一个工作版本的重载代码:
template< class F1 ,class ... Fs>
struct overload:F1,overload< Fs ...>
{
using F1 :: operator();
using overload< Fs ...> :: operator();
过载(F1 f1,Fs ... fs):F1(f1),overload< Fs ...>(fs ...){}
}
模板< class F1>
struct overload< F1> :F1
{
using F1 :: operator();
overload(F1 f1):F1(f1){}
};
template< class ... F>
auto make_overload(F ... f){
return overload< F ...>(f ...);
}
$ b $ p我还是有兴趣了解为什么这个版本的重载的lambda代码解决方案看起来像是一个Clang bug给我。
一般规则是不同基类中相同名称的成员函数不会重载。例如:
struct Foo {void bar(); };
struct Baz {void bar(int); };
struct Quux:Foo,Baz {};
int main(){Quux()。bar(); } //在GCC和Clang上的错误
无论什么原因,Clang无法诊断
operator()
。
A
命名的基类成员到派生类范围,允许它们重载。因此:
struct Quux_2:Foo,Baz {using Foo :: bar;使用Baz :: bar; };
Quux_2()。bar(); // 好。
在工作版本的代码中,
使用
声明递归地将模板参数中的每个运算符()
声明带入最大派生类的范围,允许它们重载。I'm playing with a trick to overload lambdas in C++. Specifically:
// For std::function #include <functional> // For std::string #include <string> // For std::cout #include <iostream> template <class... F> struct overload : F... { overload(F... f) : F(f)... {} }; template <class... F> auto make_overload(F... f) { return overload<F...>(f...); } int main() { std::function <int(int,int)> f = [](int x,int y) { return x+y; }; std::function <double(double,double)> g = [](double x,double y) { return x+y; }; std::function <std::string(std::string,std::string)> h = [](std::string x,std::string y) { return x+y; }; auto fgh = make_overload(f,g,h); std::cout << fgh(1,2) << std::endl; std::cout << fgh(1.5,2.5) << std::endl; std::cout << fgh("bob","larry") << std::endl; }
Now, the above program compiles and works fine in clang:
$ clang++ -g -std=c++14 test01.cpp -o test01 $ ./test01 3 4 boblarry
It does not compile in gcc:
$ g++ -g -std=c++14 test01.cpp -o test01 test01.cpp: In function 'int main()': test01.cpp:36:25: error: request for member 'operator()' is ambiguous std::cout << fgh(1,2) << std::endl; ^ In file included from test01.cpp:5:0: /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: candidates are: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = std::basic_string<char>; _ArgTypes = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}] function<_Res(_ArgTypes...)>:: ^ /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = double; _ArgTypes = {double, double}] /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int}] test01.cpp:37:29: error: request for member 'operator()' is ambiguous std::cout << fgh(1.5,2.5) << std::endl; ^ In file included from test01.cpp:5:0: /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: candidates are: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = std::basic_string<char>; _ArgTypes = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}] function<_Res(_ArgTypes...)>:: ^ /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = double; _ArgTypes = {double, double}] /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int}] test01.cpp:38:35: error: request for member 'operator()' is ambiguous std::cout << fgh("bob","larry") << std::endl; ^ In file included from test01.cpp:5:0: /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: candidates are: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = std::basic_string<char>; _ArgTypes = {std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >}] function<_Res(_ArgTypes...)>:: ^ /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = double; _ArgTypes = {double, double}] /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.2/include/g++-v4/functional:2434:5: note: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int, int}] Makefile:2: recipe for target 'all' failed make: *** [all] Error 1
Why is there a difference? For the record, I'm using gcc 4.9.2 and clang 3.5.0.
Edit 1
Evidently, this snippet of code failed to compile on VC as well and had already been reported. That being said, Sean Middleditch posted a working version of the overloaded code:
template<class F1, class... Fs> struct overload : F1, overload<Fs...> { using F1::operator(); using overload<Fs...>::operator(); overload(F1 f1, Fs... fs) : F1(f1), overload<Fs...>(fs...) {} }; template<class F1> struct overload<F1> : F1 { using F1::operator(); overload(F1 f1) : F1(f1) {} }; template <class... F> auto make_overload(F... f) { return overload<F...>(f...); }
I'm still interested in understanding why this version of the overloaded lambda code works, but the original one does not.
解决方案Looks like a Clang bug to me.
The general rule is that member functions of the same name in different base classes do not overload. For example:
struct Foo { void bar(); }; struct Baz { void bar(int); }; struct Quux : Foo, Baz { }; int main() { Quux().bar(); } // error on both GCC and Clang
For whatever reason, Clang fails to diagnose this ambiguity for
operator()
.A
using-declaration
lifts the named base class members to the derived class scope, allowing them to overload. Hence:struct Quux_2 : Foo, Baz { using Foo::bar; using Baz::bar; }; Quux_2().bar(); // OK.
In the working version of the code, the
using
declarations recursively bring everyoperator()
declaration in the template arguments into the scope of the most derived class, allowing them to overload.这篇关于C ++中的重载lambdas和clang和gcc之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!