可变参数模板专业化,std::enable_if,SFINAE
Variadic template specialization, std::enable_if, SFINAE
一个单例class公开了这个方法供客户端获取实例:
template< typename ... Args >
static T & GetInstance( Args && ... args )
{
if ( ! m_instance )
{
m_instance = new T( std::forward< Args >( args ) ... );
}
return * m_instance;
}
但是对于没有默认构造函数的classes,总是传递参数是很烦人的。最好是,一旦创建了实例,允许用户调用:
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;
}
但对于具有默认构造函数的 classes,将使用此特化 而不是 更通用的特化。我希望仅当 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<>
作为参数或模板参数而不是 return 类型吗?
这里的编译器是如何工作的?当它只是简单的模板专业化时(在 错误版本 中)我猜编译器意识到更专业的版本更适合不带参数调用 GetInstance()
的代码(T
是具有默认构造函数的 class。
对于带有 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
为空且首选时,第二个更专业。
注意。这种设计似乎很可疑。
一个单例class公开了这个方法供客户端获取实例:
template< typename ... Args >
static T & GetInstance( Args && ... args )
{
if ( ! m_instance )
{
m_instance = new T( std::forward< Args >( args ) ... );
}
return * m_instance;
}
但是对于没有默认构造函数的classes,总是传递参数是很烦人的。最好是,一旦创建了实例,允许用户调用:
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;
}
但对于具有默认构造函数的 classes,将使用此特化 而不是 更通用的特化。我希望仅当 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<>
作为参数或模板参数而不是 return 类型吗?
这里的编译器是如何工作的?当它只是简单的模板专业化时(在 错误版本 中)我猜编译器意识到更专业的版本更适合不带参数调用 GetInstance()
的代码(T
是具有默认构造函数的 class。
对于带有 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
为空且首选时,第二个更专业。
注意。这种设计似乎很可疑。