2017-10-07 70 views
1

当前我正在阅读Scott Meyers的Effective Modern C++项目15 - 尽可能使用constexpr。)。作者说:当编译时不知道参数时,不调用`constexpr`构造函数

当constexpr函数被调用与被 不是在编译期间已知的一个或多个值,它就像一个正常的功能, 计算其在运行时的结果。这意味着您不需要两个函数来执行相同的操作,一个用于编译时间 常量,另一个用于所有其他值。 constexpr函数全部都是 。

我尝试了下面的代码片段在http://coliru.stacked-crooked.com/

#include <iostream> 

class Point 
{ 
    public: 
     constexpr Point(double a, double b) noexcept 
      : _a(a), _b(b) 
     { 
     } 

     void print() const noexcept 
     { 
      std::cout << "a -> " << _a << "\tb -> " << _b << std::endl; 
     } 

    private: 
     double _a; 
     double _b; 
}; 

double get_a() noexcept 
{ 
    return 5.5; 
} 

double get_b() noexcept 
{ 
    return 5.6; 
} 


int main() 
{ 
    constexpr Point p1(2.3, 4.4); 
    p1.print(); 
    int a = get_a(); 
    int b = get_b(); 
    constexpr Point p2(a, b); 
    p2.print(); 
    return 0; 
} 

在创建p1对象一切如预期的情况:参数被称为编译时和成员被正确初始化。在创建p2对象的情况下,尽管在编译时我们不知道ab变量的值,但它应该在我的理解中起作用,因为构造函数应该充当正常函数。但我发现了以下错误信息:

main.cpp: In function 'int main()' 
main.cpp:38:28: error: the value of 'a' is not usable in a constant expression 
    constexpr Point p2(a, b); 
          ^
main.cpp:36:9: note: 'int a' is not const 
    int a = get_a(); 
     ^
main.cpp:38:28: error: the value of 'b' is not usable in a constant expression 
    constexpr Point p2(a, b); 
          ^
main.cpp:37:9: note: 'int b' is not const 
    int b = get_b(); 

Coliru使用GCC编译器。 所以,我不明白是什么问题。也许我错过了什么......

+1

你不应该申报'p2'为'constexpr',因为它不能。所以只要'点p2(a,b);''''' – songyuanyao

+0

为什么?在'p1'中,成员初始化编译时间,因为我们有编译时间的已知参数:2.3,4.4。在'p2'情况下,我们不知道'a'和'b'编译时间的值,并不意味着成员应该已经初始化了运行时? (当一个constexpr函数被调用时,有一个或多个在编译期间未知的值,它就像一个普通函数,在运行时计算其结果。) –

+1

您的报价仅指函数。如果你声明一个对象或表达式'constexpr',你需要在编译时进行评估,而'p2'不能像宋玉瑶指出的那样。 – patatahooligan

回答

6

cppreference(重点煤矿)

一个constexpr变量必须满足以下要求:

  • 它的类型必须为LiteralType
  • 必须立即初始化
  • 初始化充分表达,包括所有隐式转换,构造函数的调用等,必须是一个常量表达式

在你的榜样?

constexpr Point p2(a, b); 

... ab不是常量表达式。为了使他们常量表达式,你需要标记get_aget_ba,并且bconstexpr

constexpr double get_a() noexcept 
{ 
    return 5.5; 
} 

constexpr double get_b() noexcept 
{ 
    return 5.6; 
} 

constexpr int a = get_a(); 
constexpr int b = get_b(); 
constexpr Point p2(a, b); 
4

你误会斯科特的解释:他并不意味着你可以做constexpr具有非常量数据的对象。这样的结构不应该工作

constexpr Point p2(a, b); 

,因为编译器不知道的ab值,所以你不能申报编译器,你p2对象constexpr

他的意思是,当你定义一个constexpr函数或成员函数,这样

int constexpr foo(int a, int b) { 
    return 2*a + b; 
} 

这显然工作时,ab是编译时间常数,但它会继续甚至工作时ab是变量:

cout << foo(2, 5) << endl; // This obviously works 
int a, b; 
cin >> a >> b; 
cout << foo(a, b) << endl; // This works too 

Demo.

在你的情况下,它意味着您可以继续拨打Point的,即使变量构造函数,但你不能结果迫使constexpr

Point p2(a, b); // This works, even though Point(int,int) is constexpr 
+0

在我的情况下'a'和'b'不是变量? –

+0

其实问题在于我把'p2'声明为'constexpr'。 –

+1

@DavidHovsepyan绝对,他们是。这意味着你可以将它们传递给'constexpr'函数,但这并不意味着函数结果也会变为'constexpr'。你不能在'p2'上强制'constexpr',这是'constexpr'函数调用变量的结果。 – dasblinkenlight

相关问题