使用 enable_if 专门化模板方法

Specializing a template method with enable_if

我正在编写一个模板 class,它存储一个 std::function 以便稍后调用它。这是简化的代码:

template <typename T>
struct Test
{
    void call(T type)
    {
        function(type);
    }
    std::function<void(T)> function;
};

问题是此模板无法针对 void 类型进行编译,因为

void call(void type)

变得未定义。

将其专门用于 void 类型并不能缓解问题,因为

template <>
void Test<void>::call(void)
{
    function();
}

仍然与 call(T Type) 的声明不兼容。

所以,利用C++ 11的新特性,我尝试了std::enable_if

typename std::enable_if_t<std::is_void_v<T>, void> call()
{
    function();
}

typename std::enable_if_t<!std::is_void_v<T>, void> call(T type)
{
    function(type);
}

但它不编译 Visual Studio:

error C2039: 'type' : is not a member of 'std::enable_if'

你会如何解决这个问题?

专精整class:

template <>
struct Test<void>
{
    void call()
    {
        function();
    }
    std::function<void()> function;
};

如果您不坚持使用 void,并且您的意图是实际能够在没有任何参数的情况下使用 Test,那么请使用可变参数模板:

template <typename ...T>
struct Test
{
    void call(T ...type)
    {
        function(type...);
    }
    std::function<void(T...)> function;
};

这样,你可以有任意数量的参数。如果你想没有参数,使用这个:

Test<> t;
t.call();

所以这不完全是您想要的语法,但不需要专门化,而且此解决方案更灵活,因为支持任意数量的参数。

SFINAE 不处理(仅)class/structs 的模板参数。

在涉及方法模板参数的条件下使用模板方法。

所以你必须写

   template <typename U = T>
   std::enable_if_t<std::is_void<U>::value> call()
    { function(); }

   template <typename U = T>
   std::enable_if_t<!std::is_void<U>::value> call(T type)
    { function(type); } 

或者,如果您想确定 UT

   template <typename U = T>
   std::enable_if_t<   std::is_same<U, T>::value
                    && std::is_void<U>::value> call()
    { function(); }

   template <typename U = T>
   std::enable_if_t<std::is_same<U, T>::value
                    && !std::is_void<U>::value> call(T type)
    { function(type); } 

p.s.: std::enable_if_t 是一个类型所以不需要 typename 之前。

p.s.2:您标记了 C++11,但您的示例使用 std::enable_if_t,即 C++14,以及 std::is_void_v,即 C++17