为什么我需要在 g++ 中使用 typedef typename 而不是 VS?

2022-01-23 00:00:00 g++ c++ typedef typename

GCC 已经有一段时间没有抓住我了,但它就发生在今天.但我从来不明白为什么 GCC 需要在模板中使用 typedef typename,而 VS 和我猜想 ICC 不需要.typedef typename 是错误"还是过于严格的标准,还是留给编译器编写者的东西?

It had been a while since GCC caught me with this one, but it just happened today. But I've never understood why GCC requires typedef typename within templates, while VS and I guess ICC don't. Is the typedef typename thing a "bug" or an overstrict standard, or something that is left up to the compiler writers?

对于那些不明白我的意思的人,这里有一个示例:

For those who don't know what I mean here is a sample:

template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
    std::map<KEY,VALUE>::const_iterator iter = container.find(key);
    return iter!=container.end();
}

上面的代码在 VS 中编译(可能在 ICC 中),但在 GCC 中失败,因为它想要这样:

The above code compiles in VS (and probably in ICC), but fails in GCC because it wants it like this:

template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
    typedef typename std::map<KEY,VALUE>::const_iterator iterator; //typedef typename
    iterator iter = container.find(key);
    return iter!=container.end();
}

注意:这不是我正在使用的实际功能,而只是说明问题的一些愚蠢的东西.

Note: This is not an actual function I'm using, but just something silly that demonstrates the problem.

推荐答案

typename是标准要求的.模板编译需要两步验证.在第一次通过期间,编译器必须验证模板语法而不实际提供类型替换.在这一步中,std::map::iterator 被假定为一个值.如果它确实表示一个类型,则 typename 关键字是必需的.

The typename is required by the standard. Template compilation requires a two step verification. During the first pass the compiler must verify the template syntax without actually supplying the type substitutions. In this step, std::map::iterator is assumed to be a value. If it does denote a type, the typename keyword is required.

为什么这是必要的?在替换实际的 KEY 和 VALUE 类型之前,编译器不能保证模板不是特化的,并且特化不会将 iterator 关键字重新定义为其他内容.

Why is this necessary? Before substituing the actual KEY and VALUE types, the compiler cannot guarantee that the template is not specialized and that the specialization is not redefining the iterator keyword as something else.

您可以使用以下代码进行检查:

You can check it with this code:

class X {};
template <typename T>
struct Test
{
   typedef T value;
};
template <>
struct Test<X>
{
   static int value;
};
int Test<X>::value = 0;
template <typename T>
void f( T const & )
{
   Test<T>::value; // during first pass, Test<T>::value is interpreted as a value
}
int main()
{
  f( 5 );  // compilation error
  X x; f( x ); // compiles fine f: Test<T>::value is an integer
}

最后一次调用失败并出现错误,表明在 f() 的第一个模板编译步骤中,Test::value 被解释为一个值,但类型 X 的 Test<> 模板的实例化产生了一个类型.

The last call fails with an error indicating that during the first template compilation step of f() Test::value was interpreted as a value but instantiation of the Test<> template with the type X yields a type.

相关文章