Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ (SFINAEd)模板函数的宏_C++_Templates_Sfinae_Typetraits_Function Templates_C++17 - Fatal编程技术网

C++ (SFINAEd)模板函数的宏

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

例如,我需要在许多函数中使用它,比如这一个:

您可以通过类型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::是相同的吗;

然后,您可以使用
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
}