在前向声明类型未定义的行为上使用typeid?

时间:2012-07-04 00:31:53

标签: c++ c++11 standards

我是否在5.2.8.3: ... If the type of the expression is a class type, the class shall be completely-defined.中正确阅读标准如果类型不是“完全定义”,那是否意味着以下程序未定义?

foo.cpp:

struct foo
{
  virtual void a(){}
};

struct bar : foo
{
  virtual void a(){}
};

bar abar;

foo& get_some_foo()
{
  return abar;
}

main.cpp:

#include <iostream>
#include <typeinfo>

struct foo;

foo& get_some_foo();

int main()
{
  foo& a_ref_foo(get_some_foo());

  std::cout << "a_ref_foo typeid name: " << typeid(a_ref_foo).name() << std::endl;

  return 0;
}

MSVC10输出:`a_ref_foo typeid name:struct foo'

3 个答案:

答案 0 :(得分:13)

当我使用以下代码编译代码时

g++ foo.cpp main.cpp -o main

我明白了:

main.cpp: In function ‘int main()’:
main.cpp:12:52: error: invalid use of incomplete type ‘struct foo’
main.cpp:4:8: error: forward declaration of ‘struct foo’

这与我对标准的解释一致,即你不能将typeid应用于不完整的类型 - 而a_ref_foo属于不完整类型,因为{{1}类型的完整定义是不可见的。 foo(加上我添加的行)格式不正确,需要进行诊断。

更新:

我已经使用Visual Studio 2010 Express重现了这个问题。即使禁用语言扩展,这个简单的程序:

main.cpp

编译时没有诊断消息。使用gcc 4.7,我得到:

#include <typeinfo>

struct foo;

int main()
{
  typeid (foo);
  return 0;
}

同样的规则:

  

如果表达式的类型是类类型,则类应为   完全定义

出现在ISO,C ++标准的1998年,2003年和2012年版本中。

看起来像Visual Studio中的错误。 (如果有人想向微软报告,请继续。)

答案 1 :(得分:8)

是的,该程序格式不正确(而不是导致未定义的行为)。

如果您想知道为什么,那么您应该考虑typeid是单个运算符,但它对于多态类型的语义与非多态类型完全不同。特别是,如果foo是多态的(至少有一个虚函数,那么typeid将产生对实际类型type_info对象的引用(在这种情况bar),如果类型没有任何虚函数,那么它将返回对表达式的 static 类型的type_info对象的引用(在这种情况下) foo)。

为了使编译器生成适当的代码,编译器必须知道在使用typeid的地方,这两种情况中的哪一种适用。如果类型不完整,则编译器不会显示该信息。

答案 2 :(得分:0)

您的程序完全正确,因为函数get_some_foobar是全局变量。因此,bar已完全定义,但如果您在bar中定义main.cpp的变体,则将其用作typeid中的参数,否则在编译时会发生错误。