我正在阅读"C++编程语言 - 第四版",我正在打一个简单的练习,只是为了获得C++语法,我不小心偶然发现了让我挑眉的东西.总之,我忘了补充()
上accept
主:
bool accept() { cout << "Do you want to proceed (y or n)?\n"; char answer = 0; cin >> answer; if (answer == 'y') { return true; } return false; } int main() { accept; }
这运行并编译并生成(在VS2015中)a
C4551 - 函数调用缺少参数列表
我发现自己在阅读lambda和一些关于SO的问题应该被关闭,因为他们主要是要求"调试我的代码".
我想如果代码编译并运行,并且该函数包含一个阻塞语句(等待用户输入)和一个返回类型,那么所有代码都将按预期执行,而不管是否遗漏了括号; 但事实并非如此.
另外,我想我会将调用更改为accept
main,以bool a = accept; cout << a;
尝试阻止任何优化(如果那是实际发生的事情),并且也没有调用accept()
代码.
我很想知道的是:
accept
要编译成什么叫?
为什么不accept
调用代码
为什么这只是一个警告,而不是错误(我知道我可以更改配置以将其显示为错误,当实际结果与预期结果不同时,我更加如此质疑这是如何被接受的语法所以"显着?"这问题可能是基于意见的,如果你同意,可以省略.)
bool a = accept; cout << a;
在main中运行代码生成1
输出.这是什么时候false
是默认的bool值(至少在C#中)并且没有什么可以返回真值,因为接受代码没有被执行?
Nicol Bolas.. 13
没有"打电话accept
".见#3.
因为#1.
使用没有函数调用语法的函数名称(即:)()
意味着您正在访问函数本身.例如,您可以将其存储在函数指针中(通过函数到指针衰减):
using my_func = bool(*)(); //Function that takes nothing and returns a bool. my_func var = accept; //Store a pointer to `accept`.
然后你可以发出var();
,这会打电话accept
.
但是,因为你从不存储函数,编译器猜测你可能打算调用函数,而不是访问函数的指针.accept;
但是是一个合法的C++语句,因此编译器不能对它进行错误.它可以发出警告,因为语句没有任何结果,你可能打算调用该函数.这与以下陈述没有什么不同1;
:完全合法,但完全没用.
这样做是因为C++技巧.非空指针衰减到布尔值true
.并accept
衰减到一个非null的函数指针.因此,当转换为a时bool
,它将是true
.你还没有调用这个函数.
templatetype.. 8
在C++中,任何以分号后跟的表达式都是合法的陈述.(为什么?因为C让你这样做,我想).这意味着以下所有内容都是法律声明:
5; 3 + 5; 1 % 2 == 0;
此形式的语句的效果是表达式被计算然后被丢弃.一个好的优化编译器会消除这里的所有逻辑,因为这些都没有任何副作用.
在你的情况下,写作
accept;
是一个法律声明,因为它accept
是一个表达式,用于评估对函数的引用accept
.这意味着,accept;
声明意味着"评估地址accept
,然后丢弃它".这里没有调用函数的原因是函数名本身不调用函数; 你需要括号(函数调用运算符)来实际调用.例如,如果要将函数传递给另一个函数,这很有用.例如,您可能希望将比较函数传递给std::sort
,如下所示:
std::sort(range.begin(), range.end(), nameOfMyComparisonFunction)
在这里,如果尝试调用它将是一个真正的问题nameOfMyComparisonFunction
,因为在排序例程开始之前无法知道参数.
那为什么这是警告而不是错误?嗯,这是完全合法的C++代码,因此编译器不能顺从地将其称为错误.但是,编译器将其标记为警告是正确的,因为它几乎肯定意味着您犯了错误.也就是说,大多数编译器都有一些设置会将警告报告为错误,如果你将警告级别提高到足够高,编译器可能会说"这太可疑了,我会假设你搞砸了什么."
至于你的最后一个 - 为什么呢
bool a = accept;
最终设置a
为true?
In C++,任何非空指针都会隐式转换为true,任何空指针都会隐式转换为false.在C++中,函数可以隐式转换为指向自身的指针,因此在这种情况下accept
求值为accept
函数的地址,该函数的地址为非null,因此设置a
为true
.然后当你写
cout << a << endl;
的值被打印为1,因为bool
值被打印为1和0,而不是true
和false
默认.那就是说,你可以写
cout << boolalpha << a << endl;
你会看到true
打印而已.
希望这可以帮助!
没有"打电话accept
".见#3.
因为#1.
使用没有函数调用语法的函数名称(即:)()
意味着您正在访问函数本身.例如,您可以将其存储在函数指针中(通过函数到指针衰减):
using my_func = bool(*)(); //Function that takes nothing and returns a bool. my_func var = accept; //Store a pointer to `accept`.
然后你可以发出var();
,这会打电话accept
.
但是,因为你从不存储函数,编译器猜测你可能打算调用函数,而不是访问函数的指针.accept;
但是是一个合法的C++语句,因此编译器不能对它进行错误.它可以发出警告,因为语句没有任何结果,你可能打算调用该函数.这与以下陈述没有什么不同1;
:完全合法,但完全没用.
这样做是因为C++技巧.非空指针衰减到布尔值true
.并accept
衰减到一个非null的函数指针.因此,当转换为a时bool
,它将是true
.你还没有调用这个函数.
在C++中,任何以分号后跟的表达式都是合法的陈述.(为什么?因为C让你这样做,我想).这意味着以下所有内容都是法律声明:
5; 3 + 5; 1 % 2 == 0;
此形式的语句的效果是表达式被计算然后被丢弃.一个好的优化编译器会消除这里的所有逻辑,因为这些都没有任何副作用.
在你的情况下,写作
accept;
是一个法律声明,因为它accept
是一个表达式,用于评估对函数的引用accept
.这意味着,accept;
声明意味着"评估地址accept
,然后丢弃它".这里没有调用函数的原因是函数名本身不调用函数; 你需要括号(函数调用运算符)来实际调用.例如,如果要将函数传递给另一个函数,这很有用.例如,您可能希望将比较函数传递给std::sort
,如下所示:
std::sort(range.begin(), range.end(), nameOfMyComparisonFunction)
在这里,如果尝试调用它将是一个真正的问题nameOfMyComparisonFunction
,因为在排序例程开始之前无法知道参数.
那为什么这是警告而不是错误?嗯,这是完全合法的C++代码,因此编译器不能顺从地将其称为错误.但是,编译器将其标记为警告是正确的,因为它几乎肯定意味着您犯了错误.也就是说,大多数编译器都有一些设置会将警告报告为错误,如果你将警告级别提高到足够高,编译器可能会说"这太可疑了,我会假设你搞砸了什么."
至于你的最后一个 - 为什么呢
bool a = accept;
最终设置a
为true?
In C++,任何非空指针都会隐式转换为true,任何空指针都会隐式转换为false.在C++中,函数可以隐式转换为指向自身的指针,因此在这种情况下accept
求值为accept
函数的地址,该函数的地址为非null,因此设置a
为true
.然后当你写
cout << a << endl;
的值被打印为1,因为bool
值被打印为1和0,而不是true
和false
默认.那就是说,你可以写
cout << boolalpha << a << endl;
你会看到true
打印而已.
希望这可以帮助!