我一直在 Stack Overflow 上寻找我的问题的解决方案并看到许多类似的主题,但没有指向如此具体案例的答案。
在附带的代码中,一切正常,除非我取消注释
#define ISSUE
。然后我收到很多错误。
这里的目标是只能在类主体中声明专业化。实现需要在类定义后放在同一个文件中。
为什么这不起作用?如何让它发挥作用?
我的编译器支持 C++17,没有更新。
#include <cstdint>
#include <iostream>
#include <type_traits>
// #define ISSUE
template <typename T>
class Test
{
public:
template<typename U = T,
std::enable_if_t<
std::is_same<T, bool>::value ||
std::is_same<T, int8_t>::value ||
std::is_same<T, uint8_t>::value ||
(std::is_enum<T>::value && (sizeof(T) == 1U))
,int> = 0>
static void special(T data);
#if defined(ISSUE)
template<typename U = T,
std::enable_if_t<
std::is_same<T, int32_t>::value ||
std::is_same<T, uint32_t>::value ||
(std::is_enum<T>::value && (sizeof(T) == 4U))
,int> = 0>
static void special(T data);
#endif
};
template <typename T>
template <typename,
std::enable_if_t<
std::is_same<T, bool>::value ||
std::is_same<T, int8_t>::value ||
std::is_same<T, uint8_t>::value ||
(std::is_enum<T>::value && (sizeof(T) == 1U))
,int>>
void Test<T>::special(T data)
{
std::cout << "print 8-bit\n";
}
#if defined(ISSUE)
template <typename T>
template <typename,
std::enable_if_t<
std::is_same<T, int32_t>::value ||
std::is_same<T, uint32_t>::value ||
(std::is_enum<T>::value && (sizeof(T) == 4U))
,int>>
void Test<T>::special(T data)
{
std::cout << "print 32-bit\n";
}
#endif
int main()
{
Test<uint8_t>{}.special(5);
Test<int8_t>{}.special(5);
Test<bool>{}.special(true);
#if defined(ISSUE)
Test<uint32_t>{}.special(5);
Test<int32_t>{}.special(5);
#endif
}
只有帖子:
如何通过专门化在具有单独声明和定义的模板类方法上使用 std::enable_if
有助于获得与
#define ISSUE
一起使用的注释。
为什么这不起作用?
首先,它们只是模板函数重载,而不是成员函数的特化。
SFINAE 只能工作,如果
std::enable_if_t
的条件取决于函数的模板参数类型。这意味着,在您显示的代码中,它必须取决于U
,而不是类模板参数T
。
除此之外,
std::enable_if_t
的第二个参数是函数的返回类型,这将是 SFINAEd。您已提供 int
作为返回值,它必须是 void
(或者不提供,因为它是 std::enable_if_t
的默认类型)。
如何让它发挥作用?
我建议直接在函数签名中使用
std::enable_if_t
作为返回类型的替代方法,而不是在模板参数列表中。
您仍然可以在类之外单独保留函数的定义。
template <typename T>
class Test
{
public:
template<typename U = T>
std::enable_if_t<
std::is_same<U, bool>::value ||
std::is_same<U, int8_t>::value ||
std::is_same<U, uint8_t>::value ||
(std::is_enum<U>::value && (sizeof(U) == 1U))
> special(T data);
template<typename U = T>
std::enable_if_t<
std::is_same<U, int32_t>::value ||
std::is_same<U, uint32_t>::value ||
(std::is_enum<U>::value && (sizeof(U) == 4U))
> special(T data);
};
if constexpr
,这是该场景的更好选择。或者使用 fold 表达式 你也可以减少扩展的 std::enable_if
条件,如下所示:
// alias std::enable_if for type checking
template <std::size_t N, typename U, typename... Ts>
using enabled_types = std::enable_if_t<
(std::is_same_v<U, Ts> || ...) ||
(std::is_enum_v<U> && (sizeof(U) == N))
>;
template <typename T>
class Test
{
public:
template<typename U = T>
enabled_types<1U, U, bool, int8_t, uint8_t> special(T data);
template<typename U = T>
enabled_types<4U, U, int32_t, uint32_t> special(T data);
};