6

I am trying to write a CRTP to contain a static constexpr of the derived type, since this is impossible to do with just one class. This code compiles fine in GCC, but clang complains that Derived is an incomplete type. Which one is right?

template<class T>
class Base {
public:
    static constexpr T a = T(1), b = T(20);
};

class Derived : public Base<Derived> {
public:
    int x;
    constexpr Derived(int x) : x(x) {}
};
user975989
  • 2,578
  • 1
  • 20
  • 38
  • 1
    Be careful at Derived's constructor the local variable x and the member have the same name – Brahim Nov 05 '15 at 14:27
  • I just want to point out that keeping derived objects as static inside the base class is not the best idea.. – David Haim Nov 05 '15 at 14:28
  • The only reason for doing it this way is because I can't put a `static constexpr` of the type `Derived` into `Derived`. I wanted to be able to do this: `Derived::a` instead of something like `Derived::constants::a`. – user975989 Nov 05 '15 at 14:30
  • you can make a static method in derived that has a static object Derived that is returned. – Brahim Nov 05 '15 at 14:36
  • You might want to look at [this question](http://stackoverflow.com/questions/11928089/static-constexpr-member-of-same-type-as-class-being-defined), particularly [this answer](http://stackoverflow.com/a/32134757/3216312) states that a solution proposed there works on GCC 4.9 and 5.1, as well as clang 3.4. So you might need no CRTP at all? – Petr Nov 05 '15 at 14:36
  • justification of compiler error will be like .... definition of Derived is not complete, at the point(Inside constructor) when an instance of it was requested in `Base` class. `static constexpr T a = T(1), b = T(20);` , Now why GCC does not give an error is matter of investigation .. – g-217 Nov 05 '15 at 14:38
  • why do you have it to be `constexpr`? it's seems classic for polymorphism – David Haim Nov 05 '15 at 14:39
  • 1
    @Petr If you do that, you get issues with multiple linkage, see here http://stackoverflow.com/questions/33177955/static-constexpr-of-class-inside-class-link-problems – user975989 Nov 05 '15 at 14:42
  • @user975989, ok, I see – Petr Nov 05 '15 at 14:48

1 Answers1

2

Derived is incomplete at the point at which Base<Derived> is instantiated ([class.mem]/2), which happens right at definition time. You used constexpr, which necessitates an initializer as per [class.static.data]/3, and when Base<Derived> is instantiated, so are the declarations of its static data members ([temp.inst]/3), which includes initializers. However, the initializers are attempting to create an object of incomplete type, which is ill-formed.

You can declare your member as const instead:

template<class T>
class Base {
public:
    static const T a;
};
template <typename T>
constexpr T Base<T>::a = T(1);

since the initializer is now at the definition, the instantiation of this initializer can be deferred until e.g. Derived is complete. Demo with Clang.

Note that Clang doesn't yet treat a as constexpr because it fails to eagerly instantiate its definition. See bug #24541.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • But then you can't do `static_assert(Derived::a.x == 1, "")`, which kind of defeats the purpose of `constexpr`. – user975989 Nov 05 '15 at 14:55
  • @user975989 That appears to be a Clang bug. – Columbo Nov 05 '15 at 14:56
  • @user975989 Found the DR and added it to the answer. (Funnily enough, the example used is much on point!) – Columbo Nov 05 '15 at 14:59
  • Hmm, interesting. Why does this not cause multiple definitions as opposed to not using CTRP? – user975989 Nov 05 '15 at 15:03
  • @user975989 What do you mean? – Columbo Nov 05 '15 at 15:04
  • When I tried basically the same solution without using a template, I had the linker complain that the `constexpr`s were being defined multiple times, however this doesn't seem to be the case with this templated solution. The question: http://stackoverflow.com/questions/33177955/static-constexpr-of-class-inside-class-link-problems – user975989 Nov 05 '15 at 15:06
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/94347/discussion-between-columbo-and-user975989). – Columbo Nov 05 '15 at 15:14