首页 > 解决方案 > typename c++ 和编译顺序

问题描述

在这篇文章https://en.wikipedia.org/wiki/Typename中,涉及到关键字 Typename 的使用,是这样写的:

template <typename T>
void foo(const T& t)
{
   // declares a pointer to an object of type T::bar
   T::bar * p;
}

struct StructWithBarAsType {
  typedef int bar;
};

int main() {
   StructWithBarAsType x;
   foo(x);
}

在 StructWithBarAsType 中依赖 bar 实际上是一种类型这一事实并没有帮助,因为 foo() 可以在看到 StructWithBarAsType 之前很久就被编译。

我不明白为什么 foo() 可以在 StructWithBarAsType 之前编译很久,在这种情况下可能是这样吗?

标签: c++typename

解决方案


当编译器解析 C++ 文件时,它通常会构建一个标识符到类型的符号表。这在调用模板时很重要,因为 C++ 编译器本质上会进行“替换检查”以确保“一切正常”。

问题是这个模棱两可的陈述:

T::bar * p;

这可以解释为:

  1. T命名类型的静态成员变量bar乘以p? operator*(? T::bar, ? p)
  2. 声明类型T::bar*为 name的指针p

这在解析时会产生某种歧义,并导致编译器错误:

g++ main.cpp && ./a.out

main.cpp: In function 'void foo(const T&)':
main.cpp:9:13: error: 'p' was not declared in this scope
    9 |    T::bar * p;
      |             ^
main.cpp: In instantiation of 'void foo(const T&) [with T = StructWithBarAsType]':
main.cpp:14:9:   required from here
main.cpp:9:11: error: dependent-name 'T::bar' is parsed as a non-type, but instantiation yields a type
    9 |    T::bar * p;
main.cpp:9:11: note: say 'typename T::bar' if a type is meant

main.cpp:9:11: error: dependent-name 'T::bar' is parsed as a non-type, but instantiation yields a type

为了清除此解析错误,C++ 对“信号”进行了“语法修改”,表明模板中的标识符旨在成为类型名称而不是变量名称。这种“语法修改以以下形式出现typename

struct StructWithBarAsType {
  typedef int bar;
};

template <typename T>
void foo(const T& t)
{
   // declares a pointer to an object of type T::bar
   typename T::bar * p;
}

int main() {
   StructWithBarAsType x;
   foo(x);
}

这会编译。

请注意,与 C++ 中的解析相关的类似问题也会发生。查看最令人头疼的解析


推荐阅读