模板接受 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 int
。 T
因此推导为 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
,而不是 const
和 is 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.
...此时它死了。因此悬空。
写模板时,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 int
。 T
因此推导为 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
,而不是 const
和 is 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.
...此时它死了。因此悬空。