为什么 T& 类型的模板函数参数可以绑定到常量左值而不是右值?

Why can template function parameters of type T& be binded to const lvalues but not rvalues?

本文关键字:常量 绑定 类型 参数 函数 为什么      更新时间:2023-10-16

考虑:

template <typename T> void f(T&);
const int b = 2;
f(b);      // ok
f(2);      // error, can not bind rvalue to lvalue reference

为什么允许f(const int)?逻辑似乎表明,如果程序员没有将模板参数明确定义为const T&,他/她希望修改绑定到变量。

因此,在这种情况下,问题是,为什么模板实例化给自己提供了用常量实例化的自由,而这些常量并不是明确需要的?

即使允许模板实例化使用常量是有道理的,那么在这种情况下,为什么要禁止绑定到右值呢?您可以将右值绑定到常量左值引用。在这种情况下,模板将被实例化为f<const int>,并且f(2)将被允许。

我想知道这些决定背后的原因,而不是参考标准。

为什么允许f(const int)?

您可以用const int替换模板T,将T&转换为const int&

即使有允许模板实例化使用常量的理由,那么在这种情况下,为什么会禁止绑定到右值?

没有T(在T&中)与int&&(完全)匹配以进行推导。

f<const int>(42)是允许的,但没有发生任何扣除。

我想知道这些决定背后的原因,而不是对标准的引用。

那么为什么允许在模板中进行cv替换呢
我想说它使通用编程更容易
否则,必须为constvolatile的每个组合提供过载。

在这里,如果你想将T限制为非const,你可以使用具有特征的SFINAE:

template <typename T> std::enable_if_t<!std::is_const<T>::value> f(T&);

因此,在这种情况下,问题是,为什么模板实例化在没有明确要求常量的情况下给自己实例化常量的自由?

很简单,f的实现中没有任何东西阻止用const int实例化模板。请尝试以下操作,您会发现问题。

template <typename T> void f(T& v) { v = 3; };
const int b = 2;
f(b);      // error: assignment of read-only reference (within the template instance)
int c = 2;
f<const int>(c); // error

b是const int的事实意味着模板被实例化为<const int>,这是不可能的,因为v被修改了。类似地,不允许作为<const int>的显式实例化。

为什么它被推导为const int?它应该被推导为CCD_ 24。

如果没有明确指定实例化模板的类型,则会根据传递到函数中的类型const int来推导。期望它推导出一个不同的类型是不切实际的(如果不是完全荒谬的话)。

还请注意,如果它确实将类型推导为int,那么将const int传递到函数中会出现错误。这可以通过将模板显式实例化为<int>来证明。

template <typename T> void f(T&) {};
const int b = 2;
f<int>(b); //error: no matching function for call to 'f<int>(const int&)

在这种情况下,为什么要绑定到被禁止的右值?

编译器需要隐式地假设一个合适的类型来实例化模板,然后执行从右值到常量左值引用的隐式转换。(对我来说,这似乎是一种奢望。)

请注意,如果您将模板显式实例化为<const int>,那么将右值绑定到常量左值引用是有效的,因为可以完成转换。

template <typename T> void f(T&);
f<const int>(2);      // OK
相关文章: