我想定义一个特殊的实例,用于分支到优化的代码路径,如下所示:
//------------------ 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 task\n";
}else{
//checking for 42 first is too expensive
std::cout << "sigh, do expensive task\n";
}
}
//------------------- 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);
}
注意
Special
充当单例,以便快速决策以分支到优化算法。如果客户端使用相当于 Special
的实例,一切仍然有效,只是速度较慢。
除了示例中的最后一行之外,一切都很好。我希望
Special
为 constexpr
,但如果我在 inline
的定义中将 constexpr
替换为 Special
,编译器 (clang C++17) 会抱怨“Constexpr 变量不能具有非文字类型” ”.
Special
的正确咒语是什么(不使用单独的 .cpp 文件来表示 Thingy
)?
顺便说一下,我需要使用C++17。
据我所知,问题实际上是你的
Special
类型不完整。
目前,我能找到的唯一解决方法是添加一个额外的命名层,如下所示:
template <typename T>
class Thingy
{
const T value_;
public:
constexpr Thingy() : value_(42) {}
constexpr Thingy( T v) : value_(v){}
constexpr Thingy CombineWith( const Thingy& other) const
{
return Thingy( value_ + other.value_);
}
struct Specials;
};
template <typename T> struct Thingy<T>::Specials
{
static constexpr Thingy<T> Special{};
};
using RealThingy = Thingy<float>;
#include <iostream>
void UseThingy( const RealThingy& t = RealThingy::Specials::Special)
{
if( &t == &RealThingy::Specials::Special){
std::cout << "do cheap default task\n";
}else{
//checking for 42 first is too expensive
std::cout << "sigh, do expensive task\n";
}
}
int main()
{
UseThingy(); //should be cheap
UseThingy( RealThingy::Specials::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::Specials::Special);
return 0;
}
当编译器到达
Specials
时,Thingy
模板已经完成,因此Thingy<T>
现在是一个完整的类型,可以用作文字类型。