is_const无法正常工作以供参考

时间:2016-05-13 06:29:40

标签: c++ c++11 templates const

我写了一个测试程序:

#include <iostream> 
#include <type_traits> 
using namespace std; 
template<class T> 
void f(T&& t) 
{ 
     cout<<is_const<T>()<<endl; 
     //++t; 
} 
int main() { 
     const int i=0; 
     f(i); 
     return 0; 
} 

输出“0”,显示T不是常量!这很奇怪。然后我修改了f

template<class T> 
void f(T&& t) 
{ 
     cout<<is_const<T>()<<endl; 
     ++t; 
} 

然后出现编译错误,说我们正在修改只读t。 那么t是否可以修改?我的计划中有任何错误的假设吗?

5 个答案:

答案 0 :(得分:14)

请参阅std::is_const

  

如果T是const限定类型(即const或const volatile),则提供成员常量值等于true。对于任何其他类型,值为false。

t被声明为forwarding references。因此,对于您的代码,T将推断为const int&,这是一个参考。引用不能是 const-qualified ,它不是const本身。确切地说,没有 const引用(即int& const),因为引用不能再次反弹。 const int&是{em>到const int 的引用;并注意t因此无法修改。

从标准$8.3.2/1 References [dcl.ref]

开始
  除了cv限定符之外,

Cv限定的引用是不正确的   是通过使用typedef-name([dcl.typedef],   [temp.param])或decltype-specifier([dcl.type.simple]),在这种情况下   cv限定符被忽略。

来自cppreference的更多示例:

std::cout << std::is_const<int>::value << '\n'; // false
std::cout << std::is_const<const int>::value  << '\n'; // true
std::cout << std::is_const<const int*>::value  << '\n'; // false
std::cout << std::is_const<int* const>::value  << '\n'; // true
std::cout << std::is_const<const int&>::value  << '\n'; // false

答案 1 :(得分:4)

t是否可修改取决于T的类型,该类型是根据传入的变量类型推断出来的。在这种情况下,您传入的是const int,所以t的类型为const int &,因为您将其视为转发参考。

至于为什么is_const返回false,那是因为T引用类型和引用永远不是const。

答案 2 :(得分:3)

您的模板功能(即f)将forwarding reference(a.k.a 通用参考)作为参数。决定扣除T的规则被称为reference collapsing rules。这些规则总结如下:

  
      
  1. T& &变为T&
  2.   
  3. T& &&变为T&
  4.   
  5. T&& &变为T&
  6.   
  7. T&& &&变为T&&
  8.   

现在,根据参考折叠规则,当您作为参数提供给f int const i时,T将被扣除到int const&

根据C ++标准表52,如果is_const true符合条件, T将评估为const

enter image description here

此外,在C ++标准§20.13.4.3/ p5类型属性[meta.unary.prop] 中,有以下is_const类型特征如何工作的示例:

  

[实施例:

is_const<const volatile int>::value // true
is_const<const int*>::value // false
is_const<const int&>::value // false
is_const<int[3]>::value // false
is_const<const int[3]>::value // true
     

- 结束示例]

正如您在第三行所看到的那样is_const评估为false。为什么?因为传递给is_const作为模板参数的类型是引用类型。现在,引用本质上是const,因为你不能改变它们所引用的内容,但它们不是const合格的。因此,带引用类型的is_const将评估为false

答案 3 :(得分:0)

顶级答案是引用不具备cv资格。只有他们引用的类型才能获得cv认证。

但这是const这个词的位置重要的时候之一。当你打电话:

template<class T> 
void f(T&& t) 

左键为const intT推导出什么?您可能会说const int&(这是正确的),但看起来该类型为const (int&)。因此可能会混淆T const

但如果相反你说它推断为int const&(与以前类型相同),这里没有可能的混淆,为什么std::is_const<int const&>可能不那么令人惊讶是std::false_type

答案 4 :(得分:0)

可能的解决办法可能是在重载中拦截const类型:

template<class T> 
void f(T&& t) 
{ 
     ++t; 
} 

template<class T> 
void f(const T& t) 
{ 
     std::cout << "const here" << std::endl;
} 

然后对const对象的引用将由第二个函数处理。