constexpr data member and the one-definition-rule

  Kiến thức lập trình

I want to define a special instance that is used to branch to optimized code paths like so:

//------------------ header ----------------------
template <typename T> 
class Thingy
{
    T value_;

public:
    inline static const Thingy Special; //ODR-usable
    constexpr Thingy() : value_(42) {}
    constexpr Thingy( T v) : value_(v){}
    
    constexpr Thingy CombineWith( const Thingy& other) const
    {
        return Thingy( value_ + other.value_);
    }
};

using RealThingy = Thingy<float>;

//------------------ library ---------------------
#include <iostream>
void UseThingy( const RealThingy& t = RealThingy::Special)
{
    if( &t == &RealThingy::Special){
        std::cout << "do cheap default taskn";
    }else{
        //checking for 42 first is too expensive
        std::cout << "sigh, do expensive taskn";
    }
}

//------------------- client ---------------------
void main()
{
    UseThingy(); //should be cheap
    UseThingy( RealThingy::Special); //should be cheap
    UseThingy( RealThingy(42.)); //expensive, but that's okay
    UseThingy( RealThingy(21.)); //expensive, as it must
    
    constexpr RealThingy t1{21.}, t2{21.};
    constexpr RealThingy t3 = t1.CombineWith(t2);
    //constexpr RealThingy t4 = t1.CombineWith(RealThingy::Special);
}

Notice Special acts as a singleton for the purpose of making quick decisions to branch to optimized algorithms. If the client uses an instance equivalent to Special everything still works, it’s just slower.

All is well except the last line in the example. I want Special to be constexpr, but if I replace inline with constexpr in the definition of Special, the compiler (clang C++17) complains that “Constexpr variable cannot have non-literal type”.

What’s the correct incantation for Special (without using a separate .cpp file for Thingy)?

By the way, I’m required to use C++17.

LEAVE A COMMENT