hae*_*lix 7 c++ gcc comma nullptr c++11
我有以下测试代码:
#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);
}
Run Code Online (Sandbox Code Playgroud)
这里有两个问题但我对第二个问题最感兴趣:
为什么没有设置结果?
编辑:感谢大家的确认.我决定使用的解决方法是替换:
return result = Result::INSUCCESS, nullptr;
Run Code Online (Sandbox Code Playgroud)
以下内容:
return result = Result::INSUCCESS, (void*)NULL;
Run Code Online (Sandbox Code Playgroud)
附加说明:当然我的生产场景是使用另一种指针类型(不是void*),但为了说明的目的我进行了简化.
另一个注意事项:从解决方法中你可以看出,这个nullptr有一些可疑的东西.我猜测不编译的示例行应该实际编译,并且这两个问题可能以某种方式相关.
对于那些概述我的代码的"欺骗性"或"不可读性"的人来说,第三个也是最后一个注意事项:可读性在很大程度上是一个主观问题,例如我可以说这样的速记可以使代码更加结构化,这实际上可以帮助现货缺陷.
Sha*_*our 12
第二种情况:
return result = Result::INSUCCESS, nullptr;
Run Code Online (Sandbox Code Playgroud)
看起来像一个gcc bug,它似乎忽略了一个return语句上下文中逗号运算符的左侧,如果我将return语句更改为this(请参见实时):
return (printf("hello\n"), nullptr);
Run Code Online (Sandbox Code Playgroud)
没有输出,但如果我们在return声明之外这样做,我们得到预期的结果.它似乎是固定的,4.8但我可以用4.6和重现4.7.
如果我们看一下C++标准部分的5.18 逗号运算符它(强调我的):
用逗号分隔的一对表达式从左到右进行评估; 左表达式是废弃的值表达式(第5条).83 在与右表达式相关的每个值计算和副作用之前,对与左表达式相关联的每个值计算和副作用进行排序.结果的类型和值是右操作数的类型和值; 结果与右操作数具有相同的值类别,如果右操作数是glvalue和位域,则是一个位域.如果右操作数的值是临时值(12.2),则结果是临时值.
无论如何,正如几个人已经提到的那样,这段代码很聪明但难以阅读,因此很难维护,将其分成两行就行了.我总是想记住Brian Kernighan的这句话(可能还有其他一些版本):
每个人都知道调试的难度是首先编写程序的两倍.因此,如果你在编写它时就像你一样聪明,你将如何调试它?
对于第一种情况,如果我们看一下4.10 Pointer转换部分(强调我的未来),那么错误是有效的:
空指针常量是整数类型的整数常量表达式(5.19)prvalue,其计算结果为零 或 类型为std :: nullptr_t的prvalue.空指针常量可以转换为指针类型; 结果是该类型的空指针值,并且可以与对象指针或函数指针类型的每个其他值区分开.这种转换称为空指针转换.
表达方式:
result = Result::INSUCCESS, NULL
Run Code Online (Sandbox Code Playgroud)
不是一个常量表达式,因为它包含=,常量表达式涵盖了什么是5.19 常量表达式,并说:
条件表达式是核心常量表达式,除非它涉及以下之一作为潜在评估的子表达式(3.2)[...]
包括:
作业或复合作业(5.17); 要么
使用nullptr是可以的,因为它是std :: nullptr_t的prvalue ,我们可以从12.14.7 Pointer文字部分看到:
指针文字是关键字nullptr.它是std :: nullptr_t类型的prvalue.[注意:std :: nullptr_t是一个不同的类型,既不是指针类型也不是指向成员类型的指针; 相反,这种类型的prvalue是一个空指针常量,可以转换为空指针值或null成员指针值.见4.10和4.11.-endnote]