constexpr函数中的非constexpr调用

时间:2014-05-03 10:02:15

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

这是一个简化的例子,代码用于生成任意值的序列(在std::iota意义上)和不同类别的迭代器:

struct delta
{
    template<typename I>
    void inc(I& i) { ++i; }

    template<typename I>
    I next(I i) { inc(i); return i; }
};

有许多类delta,每个类都以不同的方式定义inc,例如--ii += stepi -= stepi *= stepf(i)等。函数next保持不变,实际上是在基类中共享。< / p>

我们正在next的变异操作中生成inc的基于值的操作。相反的做法是相同的,但是我们选择这种设计来提高性能,因为next只能在某些初始化时调用,而inc可能会被调用一百万次。

问题是如果某些参数是编译时常量,我想在编译时调用next给定constexpr参数i

这在C ++ 11中是不可能的,因为调用了非constexpr函数inc。只需更改为

template<typename I>
constexpr I next(I i) { inc(i); return i; }

template<typename I>
constexpr I next(I i) { return inc(i), i; }

不起作用。当然,我们可以提供另一个特殊功能,如

template<typename I>
constexpr I next(I i) { return i + 1; }

但这是代码重复太多,因为有许多类如delta和许多其他操作,如inc/next

我已经看到constexpr函数限制为relaxed in C++14,但我不能achieve this in practice yet

所以:

  • 最终会在C ++ 14中运行吗?
  • 标准化的现状是什么?
  • 编译器的状态是什么?
  • 任何可能的解决方法?

修改

似乎inc也应该constexpr(尽管void)。这个works就铿锵声3.4:

struct delta
{
    template<typename I>
    constexpr void inc(I& i) { ++i; }

    template<typename I>
    constexpr I next(I i) { inc(i); return i; }
};

...但不是在gcc 4.8.2上。那么上面的代码是正确的C ++ 14吗? gcc只是时间问题吗?

1 个答案:

答案 0 :(得分:4)

根据这个page C ++ 14s广义的constexpr函数尚不支持,这个例子对gcc不起作用就不足为奇了。

我认为编辑中的源代码是有效的C ++ 14,可用的草案标准here包含,第126页(第5.19节)一个与您非常相似的示例(没有模板,非成员)功能,他们使用临时):

constexpr int incr(int &n) {
    return ++n;
}

constexpr int g(int k) {
    constexpr int x = incr(k);// error: incr(k) is not a core constant
                            // expression because lifetime of k
                            // began outside the expression incr(k)
    return x;
}

constexpr int h(int k) {
    int x = incr(k);
    // OK: incr(k) is not required to be a core
    // constant expression
    return x;
}

constexpr int y = h(1); // OK: initializes y with the value 2
// h(1) is a core constant expression because
// the lifetime of k begins inside h(1)

如果我对标准的阅读是正确的,那么你的成员函数应该无关紧要,因为“this”没有被评估,而且代码似乎没有违反§5.19中所列出的任何其他规则(2 )。