Reputation: 7647
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:
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?
Upvotes: 6
Views: 6849
Reputation: 961
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).
Upvotes: 4