AOK
AOK

Reputation: 503

c++ static polymorphism (CRTP) Resulting in incomplete type when evaluating a `static constexpr`

I need access to a static constexpr and one solution I put together works with gcc (live example) but not with vc++ (live example).

The code is as follows:

template<class Drvd>
class Base
{
public:
    static constexpr bool val = Drvd::val;
};

class Derived : public Base<Derived>
{
    friend class Base;
private:
    static constexpr bool val = true;
};

int main()
{
    std::cout << Derived::Base::val << std::endl;
}

So it is a bug with vc++, but anyone has an idea on how to achieve val defined in Base as the value of val in Drvd in a different way that vc++ won't complain about?

Edit: Note that the result is the same with the variant: friend class Base<Derived>; instead of friend class Base;

Upvotes: 1

Views: 292

Answers (3)

AOK
AOK

Reputation: 503

Per @David, the problem has to do with Face being incomplete, because it goes into Base before finishing the definition of Face.

However, the solution linked to by @David is a bit old and misses some tricks of which we can take advantage. Namely, @m.s. shows us that static constexpr functions are fine - and also based on my own experimentation - and we really only need to deal with this particular case of static constexpr variables, and perhaps types accessed from Derived.

The following (live example) shows how to solve this problem, while keeping each class encapsulated to it's own h-file, making it somewhat cleaner:

#include <iostream>

// Begin: h-file of Base
template<class Drvd>
class ConstValue;

template<class Drvd>
class Base
{
public:
    static constexpr bool val = ConstValue<Drvd>::val;
};
// End: h-file of Base

// Begin: h-file of Derived
class Derived;

template<>
class ConstValue<Derived>
{
public:
    static constexpr bool val = true;
};

class Derived : public Base<Derived>
{
    friend class Base<Derived>;
private:
    static constexpr bool val = true; // optional
};
// End: h-file of Derived

// Main
int main()
{
    std::cout << Derived::Base::val << std::endl;
}

The general idea is that for each constexpr that Base needs to access from Derived, we can create a single class that encapsulate the variables, and then overload the class for each Derived that uses Base.

Upvotes: 0

David
David

Reputation: 632

your problem is not the private/friend declarations (the code wouldn't compile even if "val" was a public), your problem is that during instantiation of

static constexpr bool val = Drvd::val

Drvd is still incomplete type. See below question/answer on how to workaround this with traits classes.

C++ static polymorphism (CRTP) and using typedefs from derived classes

P.S. in fact I just flagged your question as duplicate

Upvotes: 1

m.s.
m.s.

Reputation: 16334

You could use a method:

#include <iostream>

template<class Drvd>
class Base
{
public:
    static constexpr bool val() { return Drvd::val;  }
};

class Derived : public Base<Derived>
{
    friend class Base<Derived>;
private:
    static constexpr bool val = true;
};

int main()
{
    std::cout << Derived::Base::val() << std::endl;
}

live example: https://rextester.com/IHR24393

Upvotes: 1

Related Questions