在编译时不知道参数时,不会调用`constexpr`构造函数

时间:2017-10-07 10:04:54

标签: c++ c++11 c++14

目前我正在阅读Scott Meyers' 有效的现代C ++ 第15项 - 尽可能使用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 编译器。 所以,我不明白这是什么问题。也许我错过了一些东西......

2 个答案:

答案 0 :(得分:6)

来自cppreference (强调我的)

  

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

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

在你的例子中......

constexpr Point p2(a, b);

... ab不是常量表达式。为了使它们成为常量表达式,您需要将get_aget_bab标记为constexpr

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);

答案 1 :(得分: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