假设我想在编译时构建一个图,使用一些算法,然后计算出图中有多少个节点。这似乎是一个理想的情况,而不是模板元编程,因为目标是一个计算产生一个值,而不是真正的类型。我有一些可以工作的代码,但是这个特性太新了,恐怕编译器很宽容,我可以把标准的一部分解释为我不能这么做。
#include <iostream>
struct A { int x; constexpr A(int i) noexcept : x{i} {} };
struct B { A& a; constexpr B(A& a) noexcept : a{a} {} };
constexpr int foo() {
A a{55};
B b{a};
return b.a.x;
}
template<int N>
void output()
{
std::cout << N << std::endl;
}
int main() {
// to be absolutely sure compile time eval'd,
// pass as template arg
constexpr auto b = foo();
output<b>();
}a和b实例都是在编译时创建的,它们具有相同的生存期,因此这应该是“安全的”。但是a是一个非静态对象,这部分标准似乎表示不允许这样做:
如果实体是具有静态存储持续时间的对象,该对象不是临时对象,或者是值满足上述约束的临时对象,或者是函数,则实体是常量表达式的允许结果。
我能不能?GCC和clang都对此没意见。
发布于 2015-07-31 07:22:58
是的,你的例子是一致的。
C++14松弛constexpr的特别之处在于,计算常量表达式的中间结果本身不需要是常量表达式。
return将lvalue到rvalue转换为b.a.x,因为函数按值返回,b.a.x是:
文字类型的非易失性极值,指在
e的计算范围内开始生命周期的非易失性对象。
(N4527§5.20/2.7.4)
如果您试图保存对b.a.x的(悬空)引用,这将是一个问题。这不会是你引用的“常量表达式的允许结果”。
发布于 2015-07-30 23:58:14
在你的例子中:
B b{a};b不是C++14节7.1.5 dcl.constexprp5草稿中的一个常数变量,它说:
对象声明中使用的constexpr说明符将对象声明为const。这类对象应具有文字类型,并应初始化。如果它是由构造函数调用初始化的,则该调用应该是一个常量表达式(5.19)。否则,或者如果在引用声明中使用了constexpr说明符,则其初始化项中出现的每个完整表达式都应该是一个常量表达式。注意:用于转换初始化表达式的每个隐式转换和用于初始化的每个构造函数调用都是这种完整表达式的一部分。-end注记
不适用,但如果我们稍微修改您的示例:
int main() {
constexpr auto b = foo();
A a1(42) ;
constexpr B b1( a1 ) ;
}并引入b1,这是一个constexpr变量,这将不起作用(http://melpon.org/wandbox/permlink/bQtKINMPdcxjNCM9),clang说:
error: 'B{a1}' is not a constant expression
constexpr B b1( a1 ) ;
^但是,如果我们从上面进一步修改这个示例,如下所示:
static A a1(42) ;
constexpr B b1( a1 ) ;看起来不错。一个constexpr函数是可以使用的,但是如果它不能满足要求,它就不会产生一个常量表达式。
发布于 2015-07-31 06:11:51
简而言之,您不能在编译时将非静态/临时值作为引用传递。可以将静态/全局值作为constexpr引用传递。但是,在编译时,其他任何东西都是不可用的。
constexpr void foo() {
int a; // run-time value.
...
}一个明显的解决办法是通过价值传递。它是在编译时发生的,所以您可能无法得到通常的优化,但它也发生在编译时。
http://ideone.com/J7mVj5
#include <iostream>
struct A { int x; constexpr A(int i) noexcept : x{i} {} };
struct B { A a; constexpr B(A a) noexcept : a{a} {} };
constexpr int foo() {
B b{55};
return b.a.x;
}
template<int N>
void output()
{
std::cout << N << std::endl;
}
int main() {
// to be absolutely sure compile time eval'd,
// pass as template arg
constexpr auto b = foo();
output<b>();
}另见http://ideone.com/tw4jzG
https://stackoverflow.com/questions/31735037
复制相似问题