当编译时参数未知时,不调用"constexpr"构造函数



目前我正在阅读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编译器。所以,我不明白问题出在哪里。也许我错过了什么。。。

来自cppreference(emphasis mine)

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

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

在您的示例中。。。

constexpr Point p2(a, b);

CCD_ 8和CCD_。为了使它们成为常量表达式,需要将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);

您误解了Scott的解释:他并不是说您可以用非常量数据生成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

演示。

在您的情况下,这意味着即使使用变量也可以继续调用Point的构造函数,但不能将结果强制输入constexpr:

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

最新更新