在constexpr函数中非constexpr调用

6
这是一个简化的示例代码,用于生成任意值序列(类似于 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保持不变,并且实际上在基类中共享。

我们正在从inc的突变操作生成基于值的next操作。反之亦然是等效的,但是我们选择这种设计是为了性能,因为预计只会在某些初始化时调用next,而可以调用inc一百万次。

问题在于,如果有些参数是编译时常量,则我想在给定constexpr参数i的情况下在编译时调用next

这在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函数在C ++14中限制会放宽, 但我现在还无法实践实现它。
所以:
  • 最终C ++14会起作用吗?
  • 标准化的状态是什么?
  • 编译器的状态是什么?
  • 有任何可能的解决方法吗?

编辑

看来inc也应该是constexpr(虽然是void)。 这在clang 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个回答

4
这个例子在gcc上无法运行并不令人惊讶,根据这个页面的说明,C++14的广义constexpr函数目前还未被支持。
我认为你所编辑的源代码符合C++14标准草案,这里的标准草案第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)中规定的任何其他规则。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接