c++ - 可变参数模板特化,std::enable_if,SFINAE

标签 c++ templates template-specialization sfinae

一个单例类暴露了这个方法给客户端获取实例:

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/

相关文章:

C++。似乎不接受用户的输入

template-specialization - 为什么概念类模板特化会导致错误

c++ - 为模板化容器类专门化成员函数

c++ - 具有结构定义的我的父类(super class)中的模板问题

C++模板显式声明成员函数值/避免宏问题

c++ - 使用指向在 "if"语句中声明的变量地址的指针是否可以

c++ - 在 MS VC 2013 Express 中将 C++ dll 从 32 位转换为 64 位

c++ - 如何在 C++ 中使用 lambda 作为具有默认值的模板参数?

c++ - 如何像内置类型一样提升两个模板类型进行算术运算呢?

templates - 如何使用自定义输出格式在hugo中创建适合打印机的模板