首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >是否有任何方法可以让星座对象引用/指向其他非静态的星座对象?

是否有任何方法可以让星座对象引用/指向其他非静态的星座对象?
EN

Stack Overflow用户
提问于 2015-07-30 22:18:00
回答 3查看 570关注 0票数 2

假设我想在编译时构建一个图,使用一些算法,然后计算出图中有多少个节点。这似乎是一个理想的情况,而不是模板元编程,因为目标是一个计算产生一个值,而不是真正的类型。我有一些可以工作的代码,但是这个特性太新了,恐怕编译器很宽容,我可以把标准的一部分解释为我不能这么做。

代码语言:javascript
运行
复制
#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>();
}

ab实例都是在编译时创建的,它们具有相同的生存期,因此这应该是“安全的”。但是a是一个非静态对象,这部分标准似乎表示不允许这样做:

如果实体是具有静态存储持续时间的对象,该对象不是临时对象,或者是值满足上述约束的临时对象,或者是函数,则实体是常量表达式的允许结果。

我能不能?GCC和clang都对此没意见。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 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的(悬空)引用,这将是一个问题。这不会是你引用的“常量表达式的允许结果”。

票数 5
EN

Stack Overflow用户

发布于 2015-07-30 23:58:14

在你的例子中:

代码语言:javascript
运行
复制
B b{a};

b不是C++14节7.1.5 dcl.constexprp5草稿中的一个常数变量,它说:

对象声明中使用的constexpr说明符将对象声明为const。这类对象应具有文字类型,并应初始化。如果它是由构造函数调用初始化的,则该调用应该是一个常量表达式(5.19)。否则,或者如果在引用声明中使用了constexpr说明符,则其初始化项中出现的每个完整表达式都应该是一个常量表达式。注意:用于转换初始化表达式的每个隐式转换和用于初始化的每个构造函数调用都是这种完整表达式的一部分。-end注记

不适用,但如果我们稍微修改您的示例:

代码语言:javascript
运行
复制
int main() {
    constexpr auto b = foo();
    A a1(42) ;
    constexpr B b1( a1 ) ;
}

并引入b1,这是一个constexpr变量,这将不起作用(http://melpon.org/wandbox/permlink/bQtKINMPdcxjNCM9),clang说:

代码语言:javascript
运行
复制
error: 'B{a1}' is not a constant expression
     constexpr B b1( a1 ) ;
                        ^

但是,如果我们从上面进一步修改这个示例,如下所示:

代码语言:javascript
运行
复制
static A a1(42) ;
constexpr B b1( a1 ) ;

看起来不错。一个constexpr函数是可以使用的,但是如果它不能满足要求,它就不会产生一个常量表达式。

票数 0
EN

Stack Overflow用户

发布于 2015-07-31 06:11:51

简而言之,您不能在编译时将非静态/临时值作为引用传递。可以将静态/全局值作为constexpr引用传递。但是,在编译时,其他任何东西都是不可用的。

代码语言:javascript
运行
复制
constexpr void foo() {
    int a; // run-time value.
    ...
}

一个明显的解决办法是通过价值传递。它是在编译时发生的,所以您可能无法得到通常的优化,但它也发生在编译时。

http://ideone.com/J7mVj5

代码语言:javascript
运行
复制
#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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31735037

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档