使用 lambda 的可变参数模板:g++ 错误但 运行 clang++
Variadic template using lambdas : error with g++ but running with clang++
在使用可变模板、类、函数和 lambda 时,(from here) 我发现下面的代码是 运行 clang++
而 不 运行 g++
:
#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 = "Whosebug";
char ch = 's';
cout << val << " : " << str << " : " << ch << endl;
func(val);
func(str);
func(ch);
cout << val << " : " << str << " : " << ch << endl;
return 0;
}
对于clang
:coliru
g++
:coliru
g++
为 func(val)
、func(str)
和 func(c)
给出了模棱两可的 operator()
。我认为 operator()
不能含糊不清,因为每个人都有不同的论据。
g++
有什么问题?
这与 lambda、可变参数模板、运算符或任何高级 C++1{xy} 内容无关。让我们简化一下:
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);
}
这无法在 g++
或 clang++
中编译。这也是一件好事,因为这就是指定语言的工作方式。
如果我们将 func
更改为 operator()
,g++
继续拒绝该程序,但 clang++
接受或拒绝它,具体取决于调用运算符的方式:
t.operator()(c); // rejected
t(c); // accepted
这对我来说就像一个 clang bug。
为了使上面的代码能够编译,需要做一个非常小的改动:
struct test : foo, bar {
using foo::func;
using bar::func;
};
现在我不知道如何在 using 指令中进行包扩展,或者它是否确实可行。但有一个解决方法:
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();
};
通过此更改,您的代码可以同时使用 g++
和 clang++
进行编译。
在使用可变模板、类、函数和 lambda 时,(from here) 我发现下面的代码是 运行 clang++
而 不 运行 g++
:
#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 = "Whosebug";
char ch = 's';
cout << val << " : " << str << " : " << ch << endl;
func(val);
func(str);
func(ch);
cout << val << " : " << str << " : " << ch << endl;
return 0;
}
对于clang
:coliru
g++
:coliru
g++
为 func(val)
、func(str)
和 func(c)
给出了模棱两可的 operator()
。我认为 operator()
不能含糊不清,因为每个人都有不同的论据。
g++
有什么问题?
这与 lambda、可变参数模板、运算符或任何高级 C++1{xy} 内容无关。让我们简化一下:
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);
}
这无法在 g++
或 clang++
中编译。这也是一件好事,因为这就是指定语言的工作方式。
如果我们将 func
更改为 operator()
,g++
继续拒绝该程序,但 clang++
接受或拒绝它,具体取决于调用运算符的方式:
t.operator()(c); // rejected
t(c); // accepted
这对我来说就像一个 clang bug。
为了使上面的代码能够编译,需要做一个非常小的改动:
struct test : foo, bar {
using foo::func;
using bar::func;
};
现在我不知道如何在 using 指令中进行包扩展,或者它是否确实可行。但有一个解决方法:
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();
};
通过此更改,您的代码可以同时使用 g++
和 clang++
进行编译。