我在玩C++中的lambdas重載技巧。具體做法是:C++中重載的lambdas以及clang和gcc之間的區別
// 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;
}
現在,上面的程序編譯和鐺正常工作:
$ clang++ -g -std=c++14 test01.cpp -o test01
$ ./test01
3
4
boblarry
它不會在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
爲什麼是有區別嗎?爲了記錄,我使用gcc 4.9.2和clang 3.5.0。
編輯1
顯然,這個代碼片段無法編譯的VC以及和當時已經reported。話雖這麼說,肖恩Middleditch發佈的重載代碼的工作版本:
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...);
}
我仍然有興趣瞭解爲什麼這個版本的重載拉姆達代碼的工作,但原來的一個沒有。
這可能只是因爲你簡化了這個問題的代碼,但是因爲你使用的是C++ 14,所以''(auto x,auto y){return x + y;}'會產生一個lambda具有相同的重載功能。 –
@DrewDormann當然。真的,我只是試圖拿出一個例子來展示正在發生的事情。後來,我想用它來處理更復雜的情況。 – wyer33
令人驚訝的是在clang中編譯的原始代碼。一般規則是不同基類中的相同名稱不會超載。 –