目前我正在阅读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
对象的情况下,虽然我们在编译时不知道a
和b
变量的值,但它应该在我的理解中起作用,因为构造函数应该已经充当了正常的功能。但是我收到以下错误消息:
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 编译器。
所以,我不明白这是什么问题。也许我错过了一些东西......
答案 0 :(得分:6)
来自cppreference (强调我的):
constexpr
变量必须满足以下要求:
- 其类型必须为
LiteralType
。- 必须立即初始化
- 其初始化的完整表达式,包括所有隐式转换,构造函数调用等,必须是常量表达式
在你的例子中......
constexpr Point p2(a, b);
... a
和b
不是常量表达式。为了使它们成为常量表达式,您需要将get_a
,get_b
,a
和b
标记为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);
因为编译器不知道a
和b
的值,所以你不能向编译器声明你的p2
对象是constexpr
。
他的意思是当你定义一个constexpr
函数或成员函数时,就像这样
int constexpr foo(int a, int b) {
return 2*a + b;
}
当a
和b
是编译时常量时,它显然会起作用,但即使a
和b
是变量,它也会继续有效:
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