无效地使用不完整类型,引用vs指针



下面的代码可以在Visual Studio和g++中编译和工作:

class A;
A* getRef(void);
char (&func(...))[2];
int main() {
    bool isDefault = sizeof(func(getRef()))==2;
    std::cout << isDefault << std::endl; //prints 1
    return 0;
}

下一个代码仍然在Studio中编译(并工作),但g++声明这是invalid use of incomplete type 'class A':

class A;
A& getRef(void); //the only change
char (&func(...))[2];
int main() {
    bool isDefault = sizeof(func(getRef()))==2; //g++ error here
    std::cout << isDefault << std::endl;
    return 0;
}

这是一个根本错误的代码,应该被编译器拒绝(如果是这样,为什么VS编译器不产生任何警告)?或者在这里指针和引用有什么区别只是我没有意识到?

修改后的代码的关键方面是将对不完整类型的引用作为实际实参传递给省略号形式实参。

c++ 11§5.2.2/7,关于省略号的参数:

左值到右值(4.1),数组到指针(4.2),和函数到指针(4.3)的标准转换在实参表达式上执行。具有(可能是cv限定的)类型std::nullptr_t的参数被转换为类型void*(4.10)。在这些转换之后,如果实参没有算术、枚举、指针、指向成员的指针或类类型,则程序是病态的。

对于左值到右值的转换,我们找到

c++ 11§4.1/1:<我>

非函数、非数组类型T的glvalue(3.10)可以转换为右值。如果T是不完全类型,则需要进行这种转换的程序是病态的。

当我阅读它时,但这只是我的直觉解释,对T的引用是T类型的glvalue,在这里是不完整的,产生错误的代码。

无论func的参数是什么,sizeof(func(getRef()))都将等于2。不需要对func的参数求值来得到该答案。

来自c++ 11标准:

5.3.3运算符

1 sizeof运算符返回其操作数的对象表示的字节数。操作数可以是未求值的操作数表达式(第5条),也可以是带括号的类型id

在您的示例中,操作数是一个未求值的操作数表达式。编译器不需要计算func(getRef())来得到sizeof(func(getRef()))的值。

因此,我得出结论,g++在它所需要的方面做得过火了。


看来c++对变量参数函数的处理是罪魁祸首。当func被修改为

时,它工作得很好
char (&func(A&))[2];

最新更新