#define BINDINGTEMPLATE template<typename T, typename = typename std::enable_if_t < std::is_same_v<typename std::decay_t<T>, int> || std::is_same_v<typename std::decay_t<T>, std::string> || std::is_same_v<typename std::decay_t<T>, char>>>
像这样的做法是不是很糟糕? 我在同一个类内多次使用这个函数模板。
例如,我需要在许多函数中使用它,例如:
BINDINGTEMPLATE
void myFunction(int x, int y){
dosomething specialised based on input template
}
您也可以通过类型特征实现同样的目标:
template <typename T>
using enable_if_int_or_string_or_char = std::enable_if_t <
std::is_same_v<typename std::decay_t<T>, int>
|| std::is_same_v<typename std::decay_t<T>, std::string>
|| std::is_same_v<typename std::decay_t<T>, char>>;
然后可以使用ENABLE_IF_INT_OR_STRING_OR_CHAR
代替宏。 宏有严重的缺点,所以最好的宏是不需要使用的宏。
是的,这是个坏习惯。 不要将宏用于没有宏就可以轻松完成的事情。
您可以将长SFINAE条件转换为
template <typename T> using foo = std::enable_if_t<...>;
然后你可以简单地写:
template <typename T, typename = foo<T>>
void myFunction(int x, int y)
或者,您可以将条件放入constexpr
函数或变量模板中,然后在每次使用它时编写enable_if_t
。
您还可以使用一个概念(需要C++20):
template <typename T>
concept foo = std::is_same_v<typename std::decay_t<T>, int> || etc;
template <foo T>
void myFunction(int x, int y)
请注意,使用enable_if_t
(无论您是否使用帮助器使用
)并不是非常健壮,因为用户可以通过显式指定第二个模板参数来规避它。
更好的办法是:
template <typename T, std::enable_if_t<..., std::nullptr_t> = nullptr>
void myFunction(int x, int y)
除了万无一失之外,这还允许您根据不同的特性来过载函数。
这些概念也解决了这两个问题。
IMHO,宏是蒸馏出来的邪恶。
所以,是的:(IMHO)是不好的做法。
我提出另一种方法(只是为了好玩:其他答案显示了很好的解决方案)来避免它。
您可以声明一个foo()
(SFINAE启用/禁用函数),如下所示
template <typename T>
std::enable_if_t<std::is_same_v<std::decay_t<T>, int>
|| std::is_same_v<std::decay_t<T>, std::string>
|| std::is_same_v<std::decay_t<T>, char>> foo ();
您可以使用它来编写您的最终函数
template <typename T>
decltype(foo<T>()) bar (int, int)
{ }
下面是一个完整的编译示例
#include <string>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_same_v<std::decay_t<T>, int>
|| std::is_same_v<std::decay_t<T>, std::string>
|| std::is_same_v<std::decay_t<T>, char>> foo ();
template <typename T>
decltype(foo<T>()) bar (int, int)
{ }
int main ()
{
bar<int>(0, 0); // compile
// bar<long>(0, 0); // compilation error
}