为什么不能在模板函数中将低级const类型添加到局部变量

时间:2019-06-13 13:01:08

标签: c++ c++11 templates

我正在研究c ++模板,并编写如下所示的示例:

  #include <vector>
  #include <iostream>
  #include <type_traits>
  #include <typeinfo>

  using namespace std;

  template <typename T>
  void fcn(T &&val)
  {
      cout << is_same<T, int&>::value << endl;
      const T t = val;
      //T const t = val;
      cout << typeid(t).name() << endl;
      t = 10;
      cout << "val: " << val;
      cout << ", t: " << t << endl;
      return;
  }

  int main()
  {
      cout << boolalpha;

      int i{};

      fcn(i);
   }

我希望这段代码无法成功编译,但是输出没有错误

true
i
val: 10, t: 10

我有两个问题:

  1. gcc推导T为int& type,行const T t = val意味着t const绑定到val,如下所示:const int &t = val,为什么const无效? t和i的值可以更改吗?

  2. 我用typeid(t).name()来显示t的类型,为什么只打印i

3 个答案:

答案 0 :(得分:3)

  1. 在您的情况下,const TT = int&表示给我一个我无法重新分配的参考。但是,引用永远是不可分配的,它始终指向同一对象。因此它折叠为T,在这种情况下为int&

为使其按预期工作,请使用std::remove_reference

请参阅:const references in c++ templates

  1. name返回的是实现定义的内容,因此无需多说。

答案 1 :(得分:2)

  
      
  1. gcc推断Tint&类型const T t = val,意味着t const绑定到val,为什么const没有作用?
  2.   

此功能模板签名

template <typename T> void fcn(T &&val);

使用转发参考。简而言之,当用左值int推导实例化时(根据您的情况),您最终得到T = int&,即包括引用。参考折叠将void fcn(T& &&val)转换为void fcn(T& val)

声明const T t时,这意味着T& constconst修改了左侧的内容,如果左侧没有任何内容,则修改了右侧的内容)。但这是无效的,因为没有诸如const限定的引用之类的东西,因此const限定符已被删除。

  
      
  1. 我用typeid(t).name()来显示t的类型,为什么只打印i
  2.   
不需要

typeid(t).name()输出人类可读的标识符。 i代表int,因此这取决于您的编译器。当使用clanggcc时,通常最好通过以下方式显示类型

template <class T> p(T&&) { std::cout << __PRETTY_FUNCTION__; }

p(t); // prints out understandable type info

答案 2 :(得分:0)

我写了另一个程序来研究const T,它使用“类型别名”:

  #include <iostream>                                                                                 

  using namespace std; 

  int main()                                                                                          
  {
    int i {};
    using T = int *;                                                                                
    const T t = &i;     // same with T const t = &i;                                                                                                                                                                                                                                     

    *t = 10;                                                                                                                                                                                                                                                                             
    cout << i << endl;                                                                                                                                                                                                                                                                   
    int j{};                                                                                                                                                                                                                                                                             
    //t = &j;   // error, t is int * const                                                                                                                                                                                                                                                
  } 

编译成功,输出:10

现在我可以理解为什么编译器认为const Tint * const而不是const int *,因为该编译器将T视为int这样的普通类型, char,而不是int *,这不是替代。