为什么函数名不能与返回名类型相同?
Why can't function name be the same as return name type?
不确定我缺少了什么,但为什么不编译?
class Game
{
};
class Actor
{
Game* mGame;
Game* Game() { return mGame; }
};
int main()
{
Actor a();
return 0;
}
g++-std=c++17 main.cpp-o测试
main.cpp:8:10: error: declaration of ‘Game* Actor::Game()’ changes meaning of ‘Game’ [-fpermissive]
8 | Game* Game() { return mGame; }
| ^~~~
main.cpp:1:7: note: ‘Game’ declared here as ‘class Game’
1 | class Game
|
显然,如果我将函数更改为GetGame,没有问题。只是想知道为什么——我错过了什么?
谢谢!
由于添加了语言律师标签,并且对于这是否由标准定义似乎存在一些困惑,因此标准必须说明以下内容以补充现有答案。
在[basic.scope.hiding]:
如果类名(11.2)或枚举名(9.6。
此外,在[class.name]中,我们发现:
如果在同时声明同名变量、函数或枚举器的作用域中声明类名,则当两个声明都在作用域中时,只能使用详细说明的类型说明符(6.4.4)来引用该类。[示例:
struct stat {
// ...
};
stat gstat; // use plain stat to define variable
int stat(struct stat*); // redeclare stat as function
void f() {
struct stat* ps; // struct prefix needed to name struct stat
stat(ps); // call stat()
}
--结束示例]
因此,在f
的作用域中,stat
指的是该名称的函数,而struct stat
(详细的类型说明符)指的是类。
或者在OP的例子中,在Actor
的范围中,Game
指的是该名称的(成员)函数,而class Game
(详细的类型说明符)指的是类。
请注意,或者,::Game
可以用于引用类。
最后,在[class.name]中,有一句关于编写此类代码的相关名言:
4[注意:类名的声明在类定义或精化类型说明符中看到标识符后立即生效。例如,
class A * A;
首先将A
指定为类的名称,然后将其重新定义为指向该类对象的指针的名称。这意味着必须使用精化形式class A
来引用该类。Su带有名字的ch艺术可能会令人困惑,最好避免--尾注]
因此,该标准不仅完全涵盖了这种情况,还建议不要编写这种令人困惑的代码。
考虑以下内容:
class Game
{
};
class Actor
{
Game* mGame;
Game* Game() { return mGame; }
void test() { auto g = Game(); /*constructing game or calling fn and saving ptr result?*/ }
};
当然,这可以使用::Game()
和this->Game()
来解决,但默认值是不明确的,因为标准没有说明在符号名称重用的情况下更喜欢哪个。因此,由于歧义,它不会编译。
使用当前的代码,我在编译器资源管理器上使用各种编译器对其进行了测试。。。
以下是3个不同编译器的结果、它们生成的程序集以及可能的错误或警告。所有编译器选项都设置为-std=c++17 -O3
。
x86-64 clang(中继)
asm
main: # @main
xor eax, eax
ret
警告错误
warning: empty parentheses interpreted as a function declaration [-Wvexing-parse]
其中a();
突出显示为有问题的警告
x86-64 gcc(中继)
编译失败!
警告错误
error: declaration of 'Game*' Actor::Game()' changes meaning of 'Game' [-fpermissive]
其中Game()
突出显示为问题中的错误
x64 msvc v19.24
asm
main PROC
xor eax, eax
ret 0
main ENDP
警告错误
warning C4930: 'Actor a(void)': prototyped function not called (was a variable definition intended?)
其中Actor a();
突出显示为有问题的警告
这些是基于当前代码的结果。现在让我们看看这3个相同的例子,但只修改了代码的一小部分。。。
我将把main
函数中的Actor a();
改为Actor a{};
,让我们看看它们之间的区别。。。
x86-64 clang(中继)
asm
main: # @main
xor eax, eax
ret
警告错误
没有!
x86-64 gcc(中继)
编译失败!
警告错误
error: declaration of 'Game*' Actor::Game()' changes meaning of 'Game' [-fpermissive]
其中Game()
突出显示为有问题的错误。
x64 msvc v19.24
asm
a$ = 0
main PROC
$LN3:
push rdi
sub rsp, 16
lea rax, QWORD PTR a$[rsp]
mov rdi, rax
xor eax, eax
mov ecx, 8
rep stosb
xor eax, eax
add rsp, 16
pop rdi
ret 0
main ENDP
警告错误
没有!
评估
如果比较3,你会发现Clang
和MSVC
在两种情况下都会编译,然而,它们都会在第一种情况下发出警告,在第二种情况下编译时不会出错。另一方面,GCC
在这两种情况下都无法编译,并生成完全相同的警告或编译器错误。
在第一种情况下,它是您的原始源,Clang
和MSVC
能够确定您打算调用所述类Actor
的构造函数,但会生成一条警告消息,其中GCC
在使用()
运算符时未能将其全部编译在一起。GCC
无法确定您是要呼叫Actor::Game()
还是Game::Game()
。
我们还可以推断出,Clang
和MSVC
都将其来自第一种情况的警告指向a()
,而GCC
在这两种情况下都将其错误指向Game()
。
为了进一步检查正在发生的事情,在第一种情况下,Clang
和MSVC
都生成了几乎相同的程序集。在第二种情况下,Clang
仍然生成相同的程序集,但MSVC
足迹告诉了一个完全不同的故事!
根据之间的比较,我可以在不做任何研究的情况下,根据我目前的知识说些什么
Actor a();
和
Actor a{};
我从生成的警告、错误和汇编代码中看到的行为是。。。
我相信在不同的编译器中可能是Implementation Defined
。
我不能说这是否是UB
,但我可能怀疑在某些情况下,你可以从上面生成的程序集、警告和错误中看到。。。
如果对类的构造函数使用()
运算符,那么这三个编译器中至少都存在一些歧义。GCC
甚至不编译并生成错误。Clang
和MSVC
都进行编译,其中Clang
给出空括号被解释为函数声明的警告,而MSVC
给出原型函数未被调用的警告。
然而,当我们切换到{}
运算符或初始值设定项列表时。。。Clang
生成与以前相同的程序集,但不再生成警告。MSVC
给出了一组完整的instructions
,其中两个类似乎都在构建中,并且没有生成任何警告。GCC
在这两种情况下都会崩溃,并说:"我放弃了你的意图"这是我的错误消息,总是指向Game()
!
结论
因此,为了回答您的问题:
为什么函数名称不能与返回名称类型相同?
根据使用的上下文和正在使用的编译器,它可能是相同的,对于其他编译器,他们可能会拒绝它。
那么谁能说哪个编译器的解释是准确和正确的呢。。。我没有standard
的副本,所以我不能再深入研究其中的language-lawyer
部分,但我可以概括正在发生的事情以及为什么会发生,正如我刚刚演示的那样。
我希望这种推理可以帮助您理解命名约定,以及编译器如何在将这些名称和符号转换为对象的同时尝试解释它们。
因此,在某些情况下可能存在一些歧义,而在其他情况下则没有歧义。这让我相信这是跨编译器定义的实现,因为AFAIK
标准不需要name-reuse
的特定符号,这可能会导致UB
!因此,这将不是一个好的做法,而且绝对是一种代码气味!
所有这些都与硬件架构无关!
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 将C++子类成员函数(虚拟实现)传递给 C 类型函数指针
- C++ 这里有一个返回 (24) 的布尔返回类型函数
- 使用SFINAE来检测void返回类型函数的存在
- 使用此类型函数有什么优势
- 为什么此函数通过类型函数指针调用后,呼叫明智地行为
- 如何使用无类型函数指针调用C++成员函数
- 模板返回类型函数如何在C++中工作
- 具有通用类型函数的动态库[C ]
- 如何在返回类型函数模板的专用化中使用派生类型?( "couldn't infer template argument" )
- Bon appetit :从 int 返回类型函数在 main() 中打印字符串
- 对于需要其他模板参数的类型函数的部分模板专业化
- c++错误的参数类型-函数指针
- 延迟评估模板类型函数
- 在引用或指针返回类型函数上输入
- 具有指针数据类型的非类型函数模板参数
- STL中使用的C++自定义比较类型(函数谓词与较少结构)
- C++模板基类的非类型函数模板的 using 声明
- 字符串到类型函数,模板专用化使调用统一
- 自由类型函数可以接受 Unicode 文件名吗?