使用 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); }
或者,如果您想确定 U
是 T
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
我正在编写一个模板 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); }
或者,如果您想确定 U
是 T
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