我有一个模板,如果我传递一个lambda,但是在一个相关的模板中,它将两个lambda映射到相同的模板类型,它不能推断出那个类型,并且MSVC ++ Express 2013会抱怨模板参数不明确。为了清楚起见,这里没有超载(或专业化) - 下面的两个例子是唯一具有这些标识符的实体。以下是模板,它只是在参数上应用可调用对象并返回结果:
template <class A, class OP>
auto WhichOp1(A argument, OP firstOp)->decltype(firstOp(argument)) {
return firstOp(argument);
}
template <class A, class OP>
auto WhichOp2(A argument, OP firstOp, OP secondOp)->decltype(firstOp(argument)) {
return firstOp(argument) + secondOp(argument);
}
我可以成功使用WhichOp1:
int e = WhichOp1(2, [](int i){return i * 2; });
但是对于WhichOp2的类似调用不会编译:
int d = WhichOp2(2, [](int i){return i * 2; }, [](int i){return i * 3; });
我收到以下错误:
错误C2782:&#39;未知类型chaj :: ops :: WhichOp2(A,OP,OP)&#39; :模板参数&#39; OP&#39;含糊不清
IntelliSense:没有函数模板的实例&#34; chaj :: ops :: WhichOp2&#34;匹配参数列表 参数类型是:(int,lambda [] int(int i) - &gt; int,lambda [] int(int i) - &gt; int)
我收集到的是,它根本不能将第一个lambda与第二个lambda一起使用,并在两者之间确定OP的类型应该是什么。如果我明确地实例化,它可以很好地解决歧义:
int b = WhichOp2<int, int(*)(int)>(2, [](int i){return i * 2; }, [](int i){return i * 3; });
所以我的问题只是试图更好地理解发生了什么 - 为什么编译器在将两个相似的lambda传递给公共模板参数下的模板时不能解决歧义? intellisense错误似乎将lambda的类型映射到相同的类型。如果这是编译器特定的,我不会感到惊讶,但是如果有人发现这对他们的编译器起作用,我有兴趣知道。
答案 0 :(得分:6)
每个lambda定义一个唯一的类型。即使它们采用相同的参数并返回相同的类型,两个单独的lambda仍然是两个不同的类型。
由于它们是单独的类型,因此对于编译器而言,它大致就像你曾试图做过类似的事情:
template <class T>
T foo(T a, T b) { return a + b; }
...然后尝试执行以下操作:auto x = foo(1, 2.0);
由于您传递了int
和double
,编译器无法确定是否T
是int
或double
。
在两种情况下,修复都是相同的:如果您可能正在使用lambdas,请为每个修复指定一个单独的模板参数。
请注意,这也不是lambdas独有的。如果使用显式定义的函数对象,也会发生同样的情况。例如:
struct foo {
bool operator()();
};
struct bar {
bool operator()();
};
template <class T>
void baz(T a, T b) { /* ... */ }
baz(foo(), bar());
在这里,由于您自己定义了foo
和bar
,很明显它们是两种不同的类型,即使它们都定义了相同类型的operator()
。 Lambda表达式完全相同,除了有关lambda表达式定义的类名称的次要(和不相关)细节。
答案 1 :(得分:4)
C ++标准的5.1.2/3 ([expr.prim.lambda])
章说:
lambda-expression的类型(也是闭包对象的类型)是一个唯一的,未命名的nonunion类类型
所以这一行中的两个lambdas
WhichOp2(2, [](int i){return i * 2; }, [](int i){return i * 3; });
有不同的类型,即使它们看起来一样。如果您希望WhichOp2
像这样工作,则必须使用不同的操作类型声明它:
template <class A, class OP1, class OP2>
auto WhichOp2(A argument, OP1 firstOp, OP2 secondOp)->decltype(firstOp(argument) + secondOp(argument)) {
return firstOp(argument) + secondOp(argument);
}