C++ (SFINAEd)模板函数的宏
例如,我需要在许多函数中使用它,比如这一个:您可以通过类型trait实现相同的功能:C++ (SFINAEd)模板函数的宏,c++,templates,sfinae,typetraits,function-templates,c++17,C++,Templates,Sfinae,Typetraits,Function Templates,C++17,例如,我需要在许多函数中使用它,比如这一个:您可以通过类型trait实现相同的功能: BINDINGTEMPLATE void myFunction(int x, int y) { // do something specialised based on input template } 模板 使用enable_if_int_或_string_或_char=std::enable_if_t< std::是相同的吗 ||std::是相同的吗 ||std::是相同的吗; 然后,您可以使用e
BINDINGTEMPLATE
void myFunction(int x, int y)
{
// do something specialised based on input template
}
模板
使用enable_if_int_或_string_或_char=std::enable_if_t<
std::是相同的吗
||std::是相同的吗
||std::是相同的吗;
然后,您可以使用
enable\u if\u int\u或\u string\u或\u char
来代替宏。宏有严重的缺点,所以最好的宏是您不需要使用的宏。是的,这是一种不好的做法。不要将宏用于没有宏就可以轻松完成的事情
你可以把长时间的SFINAE状态变成
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\u if_t
(无论您是否使用帮助程序using
)的这种用法不是很可靠,因为用户可以通过显式指定第二个模板参数来绕过它
更好的方法是:
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)
模板
void myFunction(int x,int y)
除了万无一失之外,这还允许您根据不同的特性重载函数
这些概念也解决了这两个问题。嗯,宏是邪恶的 所以,是的:(IMHO)是不好的做法 我提出另一种方法(只是为了好玩:其他答案显示了很好的解决方案)来避免它 您可以声明一个
foo()
(SFINAE启用/禁用函数),如下所示
template <typename T, std::enable_if_t<..., std::nullptr_t> = nullptr>
void myFunction(int x, int y)
模板
std::enable_if_t foo();
您可以使用它编写最终函数
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 ();
模板
decltype(foo())条(int,int)
{ }
下面是一个完整的编译示例
template <typename T>
decltype(foo<T>()) bar (int, int)
{ }
#包括
#包括
模板
std::enable_if_t foo();
模板
decltype(foo())条(int,int)
{ }
int main()
{
条(0,0);//编译
//bar(0,0);//编译错误
}
这是一个特征检查的示例,如果类型是您要查找的类型之一:
#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
}
模板
结构是\u int\u string\u char
{
静态常量布尔值=标准::是否相同
||std::是一样的吗
||std::是相同的;
};
您可以在编译类型中将其用作常量,使用is\u int\u string\u char::value
。在您的情况下(如果我完全理解您的代码),您可以使用以下方法简化它:
template <typename T>
struct is_int_string_char
{
static const bool value = std::is_same<std::decay<T>::type, int>
|| std::is_same<std::decay<T>::type, std::string>
|| std::is_same<std::decay<T>::type, char>;
};
<代码>模板> p>因为C++提供了许多其他选项来解决这个问题,所以不应该去宏(IMO)。 例如,您可以创建一个,其中可以指定任何传递的模板
类型
与myFunction
的模板类型T
相同,并指定解决方案
多亏了s,通过它,这个想法可以推广到任意数量的类型
,噪音更小
template <typename T, typename U = std::enable_if<is_int_string_char<T>>
#包括
#include//std::enable_if_t,std::is_same,std::disjunction_v
模板
constexpr bool isAcceptableType=std::析取;
模板
自动myFunction(TX,TY)->std::启用
{
//做点什么
}
什么是“坏习惯”纯粹是基于观点的。不过,是的。为什么用宏来代替类型特征?你是什么意思?我怎样才能多次重写这个模板呢?如果没有宏就可以实现一些东西,那么这是一个糟糕的方法,因为宏有很多缺点。请描述一下这个宏应该做什么。我在代码中添加了一个例子@MarekRbtw SFINAE很适合在不同的可选重载之间进行选择,如果您只有一个重载(如示例中所示),那么SFINAE与更简单的
静态断言相比没有任何好处,所以我给你+1。@MarekR不幸的是没有。你仍然有机会写出答案:p当我们使用decation\t
时,我们真的需要typename
?是否已在\t
别名中?
#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
}
template <typename T>
struct is_int_string_char
{
static const bool value = std::is_same<std::decay<T>::type, int>
|| std::is_same<std::decay<T>::type, std::string>
|| std::is_same<std::decay<T>::type, char>;
};
template <typename T, typename U = std::enable_if<is_int_string_char<T>>
#include <string>
#include <type_traits> // std::enable_if_t, std::is_same, std::disjunction_v
template<typename T, typename... Types>
constexpr bool isAcceptableType = std::disjunction_v<std::is_same<T, Types>...>;
template <typename T>
auto myFunction(T x, T y) -> std::enable_if_t<isAcceptableType<T, char, std::string, int>>
{
// do something
}