模板接受 const 但不接受文字

Template accepts const but not literal

写模板时,class T可以用const类型代替。

考虑:

template<class T> T& min(T& a, T& b) {
    return a < b ? a : b;
}

这适用于以下情况:

int a = 1, b = 5;
const int c = 1, d = 5;
min(a, b); // T is int
min(c, d); // T is const int

但是当用文字调用时会抛出一个编译错误(像这样):

min(1, 5); // T is const int literal

invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’

为什么? int 文字不是 const int 吗?以及如何修改模板以允许使用文字?

(与 gcc 6.3 和 MSVC 2015 一致)

文字生成一个 T& 不能接受的纯右值表达式。 T& 只接受左值。

你可以这样想:整数字面量是一个"non-living"的东西,它没有任何地址,你怎么能把它绑定到左值引用然后修改它呢?该对象将位于何处?更改将写入何处?

int 文字的类型为 int,而非 const intT 因此推导为 int,并且 int& can't bind to a prvalue.

编写这样一个函数的正确方法是完美转发参数,或者使用 const T&,两者都可以绑定到任何东西。

template<typename T, typename U>
auto min(T&& a, U&& b) -> decltype(a < b ? std::forward<T>(a) : std::forward<U>(b))
{
    return a < b ? std::forward<T>(a) : std::forward<U>(b); 
}

// Or...
template<typename T>
const T& min(const T& a, const T& b)
{
    return a < b ? a : b;
}

在完美转发参数的情况下,int a{}; min(a, 42);编译需要两个模板参数,因为它们的推导类型不同

Isn't an int literal a const int?

不,它只是一个 int,而不是 constis defined as a prvalue,因此 左值引用 不能绑定到它 - - 就像你的情况一样。

通过这样的原始模板轻松更正:

template<typename T>
const T& min(const T& a, const T& b){
    return a < b ? a : b;
}

as const T& 也将绑定到 rvalues。

避免更改或添加任何类似的内容:

template<typename T, typename U>
auto&& min(T&& a, U&& b){
    return std::forward<T>(a < b ? a : b); 
}

因为这里我们没有从物化的临时文件创建副本,因此我们有返回 悬空引用 的风险。请参阅 [class.temporary] 中的此处:

A temporary object bound to a reference parameter in a function call ([expr.call]) persists until the completion of the full-expression containing the call.

...此时它死了。因此悬空。