C++ 传递给模板函数的两个lambda使参数的类型推断不明确——为什么?

C++ 传递给模板函数的两个lambda使参数的类型推断不明确——为什么?,c++,templates,lambda,ambiguity,C++,Templates,Lambda,Ambiguity,我有一个模板,如果我传递一个lambda,它就可以工作,但是在一个相关模板中,它将两个lambda映射到相同的模板类型,它无法推断该类型,MSVC++Express 2013抱怨模板参数不明确。首先要澄清的是,这里没有重载(或专门化)——下面的两个示例是唯一具有这些标识符的实体。以下是模板,它们仅对参数应用可调用对象并返回结果: template <class A, class OP> auto WhichOp1(A argument, OP firstOp)->

我有一个模板,如果我传递一个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);
    }
但对WhichOp2的类似调用不会编译:

    int d = WhichOp2(2, [](int i){return i * 2; }, [](int i){return i * 3; });
我得到以下错误:

错误C2782:'未知类型chaj::ops::WhichOp2(A,OP,OP)':模板参数'OP'不明确

IntelliSense:没有函数模板“chaj::ops::WhichOp2”的实例与参数列表匹配 参数类型有:(int,lambda[]int(inti)->int,lambda[]int(inti)->int)

我收集到的是,它不能简单地将第一个lambda与第二个lambda结合起来,并在两者之间确定OP的确切类型。如果我显式实例化,则可以很好地解决歧义:

    int b = WhichOp2<int, int(*)(int)>(2, [](int i){return i * 2; }, [](int i){return i * 3; });
intb=WhichOp2(2,[](inti){returni*2;},[](inti){returni*3;});
因此,我的问题只是试图更好地理解正在发生的事情——为什么编译器在公共模板参数下向模板传递两个类似的lambda时不能解决歧义?intellisense错误似乎将lambda的类型映射到同一类型。我不会感到惊讶,如果这是编译器特定的,但如果有人看到这对他们的编译器,我有兴趣知道。

< P>章>代码> 5.1.2/3([ Exp.Prim.lambda)< <代码> > C++标准]:

lambda表达式的类型(也是闭包对象的类型)是唯一的、未命名的非统一类类型

所以这条线的两个lambda

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);
}
模板
auto WhichOp2(参数,OP1 firstOp,OP2 secondOp)->decltype(firstOp(参数)+secondOp(参数)){
返回第一个操作(参数)+第二个操作(参数);
}

每个lambda定义一个唯一的类型。即使它们采用相同的参数并返回相同的类型,两个单独的lambda仍然是两个单独的类型

由于它们是独立的类型,对于编译器来说,大致上就像您尝试执行以下操作:

template <class T>
T foo(T a, T b) { return a + b; }

在这里,由于您自己定义了
foo
bar
,很明显它们是两种不同的类型,即使它们都定义了相同类型的
操作符()。Lambda表达式的作用完全相同,除了Lambda表达式定义的类名称的次要(且不相关)细节。

我不仅考虑了两种类型的方法,还使用OP1和OP2作为标识符:-p我关心的是decltype尾部返回类型,它只绑定到OP1的返回类型,但是模板会让OP1和OP2有所不同。@CharlesJ.Daniels您是对的,您应该使用
decltype(firstOp(argument)+secondOp(argument))
作为尾部返回类型,请参阅更新的答案。
template <class T>
T foo(T a, T b) { return a + b; }
struct foo { 
    bool operator()();
};

struct bar {
    bool operator()();
};

template <class T>
void baz(T a, T b) { /* ... */ }

baz(foo(), bar());