2016-01-21 26 views
5

以下代码段已成功使用gcc 5.3.0进行编译,但未能使用clang 3.7.0进行编译。在这两种情况下,我使用了在线coliru编译器和相同的命令行选项:-std = C++ 14 -O2 -Wall -pedantic -pthread。参数仅用于constexpr函数体内的未评估的上下文中

#include <cstdio> 

// Definition of constexpr function 'foo'. 
constexpr std::size_t foo(const int& arg_foo) { return sizeof(arg_foo); } 

// Definition of function 'test'. 
void test(const int& arg) 
{ 
    // The following line produces an error with clang. 
    constexpr std::size_t res_foo = foo(arg); 

    // Print the result returned by the 'foo' function. 
    std::printf("res_foo = %lu\n", res_foo); 
} 

// Definition of function 'main'. 
int main(int argc, const char* argv[]) 
{ 
    // Test function call. 
    test(argc); 

    // Return statement. 
    return 0; 
} 

铛与以下错误拒绝它:

error: constexpr variable 'res_foo' must be initialized by a constant expression 
constexpr size_t res_foo = foo(arg); 
          ~~~~^~~~ 

由于两个编译器之间的这种差异,我想知道如果这是一个代码有效片。如果没有,我想更好地理解为什么会出现这种情况。

+0

海湾合作委员会的错误,很多时,它涉及到constexpr – TemplateRex

+0

@TemplateRex但是'foo'破坏constexpr函数的任何规则? – Archimaredes

+0

@Archimaredes没有,错误是''测试''arg'不是'constexpr' – TemplateRex

回答

1

您正在将constconstexpr值混合在一起。 constexpr的定义是编译时已知的值。但是argc变量只在运行时才知道(它是传递给可执行文件的一系列参数)。所以你不能把它分配给另一个constexpr变量 - res_foo。它正在从res_foo中删除constexpr定义将使您的代码可编译。

constconstexpr之间的差异可以被简化为这样的事:
const - 我不会改变这个价值
constexpr - 这个值是在编译时我不会知道改变它

我的猜测是GCC能够用O2编译这段代码,因为你没有使用arg_foo参数,并且它的大小在编译时已知。但它在语法上仍然不正确 - 编译器应该发出一个错误,因为非constexpr值被分配给一个constexpr变量。

+1

我认为他知道这一点,他的问题是因为他从来没有真正使用'argc'的值,他只需要'sizeof ',这是一个不变的表达。 – TartanLlama

+0

@TartanLlama这就是为什么gcc能够用O2编译这段代码的原因:它忽略了这个参数,因为它没有被使用并且在编译时返回一个众所周知的值。但它在语法上仍然不正确 - 编译器应该发出错误,因为非'constexpr'值被分配给'constexpr'变量。 – DennisS

+0

我知道它在语法上仍然不正确,但我认为这就是你应该在答案中解决的问题。 – TartanLlama

0

该程序格式良好,因为foo(arg)是一个在C++ 14 5.20/2中定义的prvalue核心常量表达式。特别是,在评估过程中没有左值到右值的转换,这将使其不是一个常量表达式。

+0

不是。评估需要评估与[expr.const] /2.9相违背的* id-expression *'arg':“条件表达式e是一个核心常量表达式,除非按照 的规则对e进行评估机器(1.9)将评估以下表达式之一:[...]一个id表达式,它指向引用类型的变量或数据成员,除非引用具有前面的初始化并且 - 使用常量表达式进行初始化或者 - 它是一个对象的非静态数据成员,该对象的生命周期始于e的评估内。 –

+0

5/8“未评估未评估的操作数。” – aschepler

+0

是的,它不在'foo'里面评估。但是它在外部进行评估以获得参数传递。评估'foo(arg)'的第一步是评估'foo'和'arg'。 –