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

3

我正在学习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 常量绑定到 val,就像这样:const int &t = val,为什么 const 没有效果?t 和 i 的值可以改变吗?

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

3个回答

3
  1. 在您的情况下,T = int&const T 意味着“给一个无法重新赋值的引用”。但是,引用永远不可分配,它始终指向同一对象。因此,它会折叠成为 T ,在这种情况下为 int&

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

参见: const references in c++ templates

  1. name 返回的内容是实现定义的,因此关于它没有太多可说的。

2
  1. gcc推断出Tint&类型,const T t = val表示t常量绑定到val,为什么const没有效果?

这个函数模板签名

翻译说明:本文中的“gcc”指GNU编译器套件。

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

最初的回答: 使用了一个转发引用。简而言之,当使用一个左值int(您的情况)推断出实例化时,您最终得到T = int&,即包括引用。引用折叠将void fcn(T& && val)转换为void fcn(T& val)。
当您声明const T t时,这意味着T& const(const修改其左侧内容,如果左侧没有任何内容,则修改其右侧内容)。但是这是无效的,因为不存在const限定的引用,因此const修饰符被删除。
  1. 我使用typeid(t).name()来显示t的类型,为什么只打印i
typeid(t).name() 不需要输出人类可读的标识符。 i代表int,因此根据编译器的不同,这就是您应该期望的。在使用clang或gcc时,通过以下方式显示类型通常更好:
template <class T> p(T&&) { std::cout << __PRETTY_FUNCTION__; }

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

我认为const修改右边的内容,而不是左边。 - Heng Zhang
非常感谢您的建议,PRETTY_FUNCTION 看起来更好。 - Heng Zhang

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 视为像 intchar 这样的普通类型,而不是像 int * 这样的替代类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接