Question

This is a simplified example from code meant to generate sequences of arbitrary values (in the sense of std::iota) and iterators of varying categories over them:

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

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

There are many classes like delta, each defining inc differently, e.g. --i, i += step, i -= step, i *= step, f(i) etc. Function next remains the same and is actually shared in a base class.

We are generating the value-based operation of next from the mutating operation of inc. Doing the opposite would be equivalent, however we choose this design for performance, because next is only expected to be called at some initialization, while inc may be called a million times.

The problem is that in case some parameters are compile-time constant, I would like to call next at compile-time given a constexpr argument i.

This is not possible in C++11 because of the call to non-constexpr function inc. Simply changing to

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

or

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

will not work. Of course, we could provide another special function like

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

but this is too much code duplication, given that there are many classes like delta and many other operations like inc/next.

I have seen that constexpr function restrictions are to be relaxed in C++14, but I cannot achieve this in practice yet.

So:

  • will this work in C++14 eventually?
  • what is the status of standardization?
  • what is the status of compilers?
  • any possible workaround?

EDIT

It seems inc should be constexpr as well (though void). This works on 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; }
};

...but not on gcc 4.8.2. So is the code above correct C++14? Is it only a matter of time for gcc?

Was it helpful?

Solution

It is not surprising that this example does not work on gcc, according to this page C++14s generalized constexpr functions are not yet supported.

I believe the source code in your edit is valid C++14, the Draft Standard available here contains, on page 126(§5.19) an example that is very similiar to yours(without template, non member functions and they use a temporary):

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)

If my reading of the Standard is correct, the fact that yours are member functions should not matter, because "this" is not evaluated and it seems like the code does not violate any of the other rules outlaid in §5.19(2).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top