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.