传递const类型的地址时模板参数推断失败

Sau*_*ahu 14 c++ templates compiler-errors const

template <typename T>
T go(T a, T *b){ T *t; return *t;}

int main() {
    const int x = 10;
    go(x, &x);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

给编译器错误:

错误:没有用于调用'go(const int&,const int*)'的匹配函数

为什么第一个参数是引用类型const int&而不是仅仅const int

为了解决这个编译错误,我通过指定参数的类型来覆盖编译器推导过程go<const int>(x, &x);,但为什么我还需要这样做呢?

Rei*_*ica 13

这是类型演绎的冲突.从第一个参数T推断出来,intconst int第二个参数推断出来.因此,类型推导失败(并且编译器呈现的消息可能会或可能不会使根本原因明确).

如果你想让这个函数工作而不必明确指定模板参数,你可以使它只有第二个函数参数驱动扣除:

template <class T>
struct NonDeduced { using type = T; }

template <class T>
T go(typename NonDeduced<T>::type a, T *b) { T *t; return *t; }
Run Code Online (Sandbox Code Playgroud)

这样,T只能从第二个参数中推导出来,并且第一个参数将使用推导T而不进行修改.


son*_*yao 6

因为a声明是按值传递的,所以在模板参数推导中:

c)否则,如果A是cv限定类型,则忽略顶级cv限定符以进行推导:

这意味着,对于go(x, &x);第一个参数x,模板参数T将被推导为int,而不是const int.因为第二个参数T将被推断为const int,因为b声明被指针传递(并且被指向的对象上的cv限定符被保留;对于传递引用也会发生同样的事情).然后扣除失败.


BTW:clang给出了相当明确的信息:

prog.cc:4:3:注意:候选模板被忽略:推导出参数'T'的冲突类型('int'与'const int')