一个单例类暴露了这个方法给客户端获取实例:
template< typename ... Args >
static T & GetInstance( Args && ... args )
{
if ( ! m_instance )
{
m_instance = new T( std::forward< Args >( args ) ... );
}
return * m_instance;
}
但是对于没有默认构造函数的类,总是传递参数是很烦人的。最好在创建实例后允许用户调用:
auto & instance = GetInstance( );
起初我认为要让它工作,只需要专门化模板化方法,比如:
// Wrong Version
template< >
static T & GetInstance< >( )
{
if ( ! instance )
{
throw std::runtime_error(
"Tried to get instance of non initialized singleton with no"
" default constructor." );
}
return * instance;
}
但对于具有默认构造函数的类,将使用此特化代替更通用的类。我希望仅当时才使用这种特化 T
没有默认构造函数。
所以我试着稍微改变一下:
// Right Version
template< >
static auto GetInstance< >( ) ->
typename std::enable_if<
! std::is_default_constructible< T >::value , T & >::type
{
if ( ! instance )
{
throw std::runtime_error(
"Tried to get instance of non initialized singleton with no"
" default constructor." );
}
return * instance;
}
所以这行得通,但我对整个事情感到困惑。首先,我的处理方式是否正确?我不应该使用 enable_if<>
吗?作为参数或模板参数而不是返回类型?
编译器在这里是如何工作的?当它只是简单的模板特化时(在错误的版本中)我猜编译器意识到更专业的版本更适合代码调用 GetInstance()
没有参数(T
是一个带有默认构造函数的类)。
对于带有 enable_if<>
的版本, 编译器开始考虑使用更专业的版本会更好,但代码格式不正确。所以它回退到通用版本?这也叫SFINAE吗?
最佳答案
实用的经验法则:不要专门化,重载。
template <class... Args>
static T& GetInstance(Args&&... );
template <class U=T, std::enable_if_t<!std::is_default_constructible<U>::value, int> = 0>
static T& GetInstance();
如果 T
是默认可构造的,则您只有一个可行的重载。如果不是,则当 Args
为空且首选时,第二个更专业。
注意。这种设计似乎很可疑。
关于c++ - 可变参数模板特化,std::enable_if,SFINAE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41269722/