模糊的情况下的typename解析

时间:2011-11-16 01:37:59

标签: c++ visual-c++

我正在玩Visual Studio和模板。

考虑这段代码

struct Foo
{
  struct Bar
  {
  };

  static const int Bar=42;
};

template<typename T>
void MyFunction()
{
  typename T::Bar f;  
}

int main()
{
    MyFunction<Foo>();
    return 0;
}

当我编译它是Visual Studio 2008和11时,我收到以下错误

error C2146: syntax error : missing ';' before identifier 'f'

Visual Studio在这方面是否正确?代码是否违反任何标准?

如果我将代码更改为

struct Foo
{
  struct Bar
  {
  };

  static const int Bar=42;
};


void SecondFunction( const int& )
{
}

template<typename T>
void MyFunction()
{
  SecondFunction( T::Bar ); 
}

int main()
{
    MyFunction<Foo>();
    return 0;
}

它编译时没有任何警告。在Foo :: BLAH中,成员首选类型,以防发生冲突?

关于G ++ 4.2.1的EDIT测试

struct Foo
{
  static const int Bar=42;
};


void SecondFunction(const int& x)
{
}

template<typename T>
void MyFunction()
{
  int x = Foo::Bar;
}

int main()
{
  MyFunction<Foo>();
  return 0;
}

编译好。

struct Foo
{
  static const int Bar=42;
};


void SecondFunction(const int& x)
{
}

template<typename T>
void MyFunction()
{
  SecondFunction(T::Bar);
}

int main()
{
  MyFunction<Foo>();
  return 0;
}

给我这些错误

未定义的符号:   “Foo :: Bar”,引自:       void cck498aS.o中的MyFunction() ld:找不到符号 collect2:ld返回1退出状态

2 个答案:

答案 0 :(得分:3)

在C ++中,命名实体属于三个不同的本体层之一:类型模板

如果从属名称是未知层,那么必须告诉编译器它是什么:

  • 如果你什么都不说,那就是一个价值。

  • 如果你说typename,那就是一种类型。

  • 如果你说template,那就是模板。

因此T::Bar作为MyFunction模板中的从属名称,会自动被假定为引用某个值,因此int成员Foo::Bar。另一方面,在第一个示例中,typename T::Bar确实是指成员类型 Foo::Bar

答案 1 :(得分:3)

您会看到存在C兼容性的不为人知的规则的效果。在C中,与C ++不同,如果将类型定义为struct Xenum X,则将名称X引入相应的命名空间,但是将类型称为struct X。因此,在C中,您还可以将“X”定义为不同的东西,而不会触发相互冲突的定义。现在在C ++中,struct X确实将名称X引入相应的范围。因此,X的任何其他定义都将被标记为双重定义。但是,能够包含经常出现此问题的C标头被认为是重要的。因此,引入了一条特殊规则,即只要您同时拥有X的(非typedef)类型定义和X的另一个定义,这不会导致错误,但X引用对于非类型定义,要获得类型定义,您必须在其前面加上相应的类型关键字(即struct Xemum Xclass X)。

在您的情况下,这意味着Foo包含名为class Bar的类型和名为Bar的静态const int,但没有名为Bar的类型。请注意,此处不需要模板;一个简单的全局声明Bar::Foo foo;也应该失败。