0

I want to implement a compile-time getter in a way to make its call more concise. I have a non-type (unsigned int N) class template foo, which recursively inherits from foo<N - 1>. Every foo has its own enum member called number, which is initialized to the value of its corresponding N. The base case is foo<0>. For example, a foo<5> object has 6 enums called number, valued 0 through 5. I want to implement a compile-time getter at, but it's not as easy as prepending a constexpr to the prototype:

template <unsigned int N>
struct foo : protected foo<N - 1> {
protected:
    enum {number = N};
public:
    constexpr int const& at(const unsigned int index) {
        static_assert(index <= N, "out of range");
        return this->foo<index>::number;
    }
};

template <>
struct foo<0> {
protected:
    enum {number = 0};
public:
    constexpr int const& at(const unsigned int index) {
        static_assert(index == 0, "out of range");
        return this->number;
    }
};

In g++ 4.8, I get several instances of the errors: error: 'index' is not a constant expression, among other things. The rest just follow suit. Even if all client code calls at with integer literals only, the getter won't compile. Why?

In any case, my solution was to implement a compile-time integer wrapper. It's simply a non-type (unsigned int N) class template ctint (short for compile-time int), whose enum member mem is initialized to its N:

template <unsigned int N>
struct ctint {
    enum {mem = N};
};

So, replacing foo<N> and foo<0>'s getter methods, respectively, with:

template <unsigned int ind>
constexpr int const& at(ctint<ind> const& ctint_par) {
    static_assert(ctint_par.mem <= N, "out of range");
    return this->foo<ctint_par.mem>::number;
}

and

template <unsigned int ind>
constexpr int const& at(ctint<ind> const& ctint_par) {
    static_assert(ctint_par.mem == 0, "out of range");
    return this->number;
}

works:

int main() {
    foo<5> f;
    static_assert( f.at( ctint<4>{} ) != 4 , "equals 4");
}

but makes the function call verbose. I’d like an implementation that’s library-free aside from parts (e.g. <iostream>) that show something works but not help make it work. I’d like the getter to be able to optionally omit or have no <> syntax or spelling out of a type name in the call, but not necessarily in the prototype or definition. I don't want it to involve array[]s. If that’s impossible, I’d like to know the next-best way.

CodeBricks
  • 1,771
  • 3
  • 17
  • 37
  • Why can't you just do `template constexpr int at() { ... }`? – David G Dec 24 '13 at 01:57
  • @0x499602D2, I'd prefer not to involve `<>` syntax in the call. – CodeBricks Dec 24 '13 at 01:58
  • It's the only way you've narrowed it down to. You have to supply it as a template argument. – David G Dec 24 '13 at 01:59
  • Didn't you [already ask this question](http://stackoverflow.com/q/20724456/596781)? – Kerrek SB Dec 24 '13 at 02:01
  • @KerrekSB, I'm not sure if the prior's solution applies here. The difference is I don't want to use arrays or `<>` syntax in the call here. Though the integer wrapper is re-implemented here, I don't think they are the same question. The inheritance recursion makes that prior question's accepted answer's getter inapplicable here. – CodeBricks Dec 24 '13 at 02:02
  • @0x499602D2, Why doesn’t the first, broken `at` code work even if I call it with an integer literal? A call to a normal non-member `constexpr int bar(int index) {…}` works with a literal within a `static_assert`. Why does the `N` cause a literal passed to `index` to **not** be a compile-time constant? – CodeBricks Dec 24 '13 at 02:21
  • 1
    Regarding the first example, see e.g. [this question](http://stackoverflow.com/q/17577749/420683). Essentially, a function parameter of a `constexpr` function is not *assumed* to be a compile-time constant. – dyp Dec 24 '13 at 02:35
  • 1
    `template using ctint = std::integral_constant;` (i.e. it already exists in the Standard Library). Also, the `const&` aren't useful as far as I can see in these examples. – dyp Dec 24 '13 at 02:41
  • 1
    What about user-defined literals? `f.at( 4_cint )` [Live example](http://coliru.stacked-crooked.com/a/67dff34294a8a225) – dyp Dec 24 '13 at 02:50
  • @DyP, [This answer](http://stackoverflow.com/a/14248310/2090317) says: "`constexpr` functions will be evaluated at compile time when all its arguments are constant expressions and the result is used in a constant expression`." If my code fails to compile, preventing me from instantiating any objects, how would it know I planned to call my getter with a non-literal or call it with a literal and not use the result in a constant expression? – CodeBricks Dec 24 '13 at 02:51
  • 1
    I'm not sure if I understand you correctly, but the `constexpr` function itself must be written in a way so that it *can* be called with arguments only known at run-time. That's why it isn't assumed that the parameters are compile-time constants. – dyp Dec 24 '13 at 02:54
  • It must also be written so that if for *some arguments*, if those arguments are known at compile-time, the function can be evaluated at compile-time. E.g. in a constant expression. But nothing is assumed about when the function is actually called later; it just has to satisfy those two requirements: 1) for some arguments, it must be evaluable at compile-time 2) it must be evaluable for arguments known only at run-time. – dyp Dec 24 '13 at 02:59
  • @DyP, +1 for pro code.In my broken code, if I pass literal to `at`, then it’s known at compile-time.But compiler errors remove my chance to pass literal to `at`. I [**commented out stuff here**](http://coliru.stacked-crooked.com/a/200ec1341efce1a7) so that `index` isn’t used to look up base subobjects. Is that the difference for the function's constant-expression-ness? I’m guessing the compiler doesn’t allow possibility of using `index` to look up subobjects since there’s possibility `at` is called at runtime with wrong value, evaluating nonexistent bases.Is this un-SFINAE for function bodies? – CodeBricks Dec 24 '13 at 03:37
  • 1
    have you checked http://stackoverflow.com/questions/14309245/single-expression-helper-for-compile-time-enforced-constexpr-function-evaluation? – oblitum Dec 24 '13 at 05:46
  • 2
    Your first `constexpr` function using `return this->foo::number` violates the second point I mentioned: At run-time, there *are no templates and no types*, `foo` **must** be resolved at compile-time. And that's of course not possible if we don't assume `index` is a compile-time constant (initialized with a constant expression). Similarly, `static_assert` is a compile-time feature. However, instead of `static_assert`, you can [throw an exception to raise a compile-time error](http://stackoverflow.com/a/8626450/420683). – dyp Dec 24 '13 at 10:59

0 Answers0