单例类为客户端公开此方法以获取实例:
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吗?
答案 0 :(得分:4)
方便的经验法则:不专业化,超载。
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
为空并且是首选时,第二个更专业。
请注意。这种设计似乎令人怀疑。