我有以下测试代码:
#include <cstdint>
#include <cassert>
enum class Result : std::uint32_t {SUCCESS = 0, INSUCCESS = 1};
void* func(Result& result)
{
// works great
/*
result = Result::INSUCCESS;
return NULL;
*/
// error: invalid conversion from ‘long int’ to ‘void*’ [-fpermissive]
/*
return result = Result::INSUCCESS, NULL;
*/
// compiles, but <result> is not set???
return result = Result::INSUCCESS, nullptr;
}
void testReturnWithSideEffects()
{
Result result = Result::SUCCESS;
func(result);
assert(result == Result::INSUCCESS);
}
这里有2个问题,但我对第二个问题最感兴趣:
为什么没有设置结果?
编辑: 感谢大家的确认。我决定使用的解决方法是替换:
return result = Result::INSUCCESS, nullptr;
以下内容:
return result = Result::INSUCCESS, (void*)NULL;
补充说明:当然我的制作方案是使用另一种指针类型(不是void *),但为了说明的目的我进行了简化。
另一个注意事项:从解决方法中你可以看出,那个nullptr还有一些可疑的东西。我猜测不编译的示例行应该实际编译,并且这两个问题可能以某种方式相关。
还有第三个也是最后一个注释,对于那些勾勒出&#34;技巧&#34;或者&#34;不可读性&#34;我的代码:可读性在很大程度上是一个主观问题,例如我可以说这样的简写可以使代码更加结构化,实际上可以帮助发现缺陷。
答案 0 :(得分:12)
第二种情况:
return result = Result::INSUCCESS, nullptr;
看起来像一个gcc bug,如果我将return
语句更改为this( see it live,它似乎忽略了return语句上下文中逗号运算符的左侧} 的):
return (printf("hello\n"), nullptr);
没有输出,但如果我们在return
语句之外执行此操作,则会获得预期结果。它似乎已在4.8
中修复,但我可以使用4.6
和4.7
进行复制。
如果我们查看draft C++ standard部分5.18
逗号运算符,它会说(强调我的):
用逗号分隔的一对表达式从左到右进行评估;左表达式是一个废弃的值表达式(第5条)。 83 在与右表达式相关的每个值计算和副作用之前,对与左表达式相关的每个值计算和副作用进行排序< / strong>即可。结果的类型和值是右操作数的类型和值;结果与右操作数具有相同的值类别,如果右操作数是glvalue和位域,则是一个位域。如果右操作数的值是临时值(12.2),则结果是临时值。
无论如何,有几个人已经提到这个代码很聪明但很难阅读,因此难以维护,将其分成两行就行了。我总是想记住这个quote from Brian Kernighan(可能还有其他一些版本):
每个人都知道调试的难度是首先编写程序的两倍。因此,如果你在编写它时就像你一样聪明,你将如何调试它?
对于第一种情况,如果我们查看4.10
指针转换部分(强调我的前进),则错误有效:
空指针常量是整数常量表达式(5.19) 整数类型的prvalue,其评估为零 或 类型的prvalue 的std :: nullptr_t 。空指针常量可以转换为指针 类型;结果是该类型的空指针值,并且是 可以与对象指针或函数的每个其他值区分开来 指针类型。这种转换称为空指针转换。
表达式:
result = Result::INSUCCESS, NULL
不是常量表达式,因为它包含=
,5.19
常量表达式部分涵盖了什么是常量表达式,并说:
条件表达式是核心常量表达式,除非它 涉及以下之一作为潜在评估的子表达式 (3.2)[...]
并包括:
作业或复合作业(5.17);或
使用 nullptr 是可以的,因为它是 std :: nullptr_t 的prvalue,我们可以从12.14.7
部分指针文字看到其中说:
指针文字是关键字nullptr。 这是一种类型的prvalue 的std :: nullptr_t 即可。 [注意:std :: nullptr_t是一个独特的类型 既不是指针类型也不是指向成员类型的指针;相反,一个prvalue 此类型是空指针常量,可以转换为null 指针值或null成员指针值。见4.10和4.11。 -endnote]
答案 1 :(得分:0)
我的测试表明您的代码应该有效。我在compileonline.com上运行了这个:
#include <iostream>
using namespace std;
int func5() {
return 5;
}
int func(int& result) {
return result = func5(), 10;
}
enum class Result : uint32_t {SUCCESS = 0, INSUCCESS = 1};
void* func(Result& result)
{
// works great
/*
result = Result::INSUCCESS;
return NULL;
*/
// error: invalid conversion from ‘long int’ to ‘void*’ [-fpermissive]
/*
return result = Result::INSUCCESS, NULL;
*/
// compiles, but <result> is not set???
return result = Result::INSUCCESS, nullptr;
}
int main()
{
int b = 0;
int a = func(b);
cout << a << ", " << b << endl;
Result result = Result::SUCCESS;
func(result);
cout << uint32_t(result) << endl;
}
结果:
Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1
Executing the program....
$demo
10, 5
1
也许你的编译器有错误?
答案 2 :(得分:-2)
引用C ++标准 - 逗号运算符:
结果的类型和值是右操作数的类型和值
所以你得到了#null; nullptr&#39;,它被转换为结果,也是SUCCESS。