1

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;

AOK
  • 493
  • 5
  • 16
  • Possible duplicate of [C++ static polymorphism (CRTP) and using typedefs from derived classes](https://stackoverflow.com/questions/6006614/c-static-polymorphism-crtp-and-using-typedefs-from-derived-classes) – David Mar 19 '19 at 15:38

3 Answers3

1

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

m.s.
  • 16,063
  • 7
  • 53
  • 88
  • Nice variant, but I would have to resort to adding `()`. If nothing else, I guess this would have to do. Thanks. – AOK Mar 19 '19 at 13:39
  • 1
    One other comment, using a `constexpr` function, while working for this particular case, is also limiting in being able to use `val()` as a template parameter. – AOK Mar 19 '19 at 14:01
1

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

David
  • 602
  • 5
  • 14
  • thanks, this seems to be the right direction. Although I'm not sure if it's directly a duplicate, but I will try to play around with the information on the other page and see what results. – AOK Mar 19 '19 at 15:59
0

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.

AOK
  • 493
  • 5
  • 16