Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.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++ 枚举的空变量包--它们使两个函数不同吗?_C++_Templates_C++11_Language Lawyer_Sfinae - Fatal编程技术网

C++ 枚举的空变量包--它们使两个函数不同吗?

C++ 枚举的空变量包--它们使两个函数不同吗?,c++,templates,c++11,language-lawyer,sfinae,C++,Templates,C++11,Language Lawyer,Sfinae,在重写模板函数时,我有时会使用这样一种技术: #include <utility> template<int> struct unique_enum { enum class type {}; }; template<int index> using UniqueEnum = typename unique_enum<index>::type; template<bool b, int index=1> using EnableFunc

在重写
模板
函数时,我有时会使用这样一种技术:

#include <utility>
template<int> struct unique_enum { enum class type {}; };
template<int index> using UniqueEnum = typename unique_enum<index>::type;
template<bool b, int index=1>
using EnableFuncIf = typename std::enable_if< b, UniqueEnum<index> >::type;
template<bool b, int index=1>
using DisableFuncIf = EnableFuncIf<!b, -index>;

// boring traits class:
template<typename T>
struct is_int : std::false_type {};
template<>
struct is_int<int> : std::true_type {};

#include <iostream>
// use empty variardic packs to give these two SFINAE functions different signatures:
template<typename C, EnableFuncIf< is_int<C>::value >...>
void do_stuff() {
  std::cout << "int!\n";
}
template<typename C, DisableFuncIf< is_int<C>::value >...>
void do_stuff() {
  std::cout << "not int!\n";
}

int main() {
  do_stuff<int>();
  do_stuff<double>();
}
#包括
模板结构唯一_enum{enum类类型{};};
使用uniquenum=typename unique_enum::type的模板;
模板
使用EnableFuncIf=typename std::enable_if::type;
模板
使用DisableFuncIf=EnableFuncIf;
//令人厌烦的特性类:
模板
结构是_int:std::false_type{};
模板
结构是_int:std::true_type{};
#包括
//使用空变量包为这两个SFINAE函数提供不同的签名:
模板…>
void do_stuff(){
标准::cout
void do_stuff(){

std::cout我认为GCC是正确的,您的技术也是正确的。基本上,由于明确指定了
C
的类型参数,问题是:

a、 首先替换函数模板签名中的
C
,然后执行类型推断(这将导致替换失败);或

b、 首先执行类型推断,然后执行替换(这不会导致替换失败,因为相应的参数包将为空,因此不会执行替换)

似乎GCC假设为(1),而Clang假设为(2)。C++11标准第14.8.2/2段规定:

指定显式模板参数列表时,模板参数必须与 模板参数列表,并且必须生成如下所述的有效函数类型;否则为类型推断 失败。具体而言,在评估明确指定的模板时执行以下步骤 关于给定函数模板的参数列表:

-指定的模板参数必须与模板参数实物匹配(即类型、非类型、, 模板)。除非至少有一个参数,否则参数不能多于参数 是一个模板参数包,每个非包参数都应该有一个参数,否则, 类型扣除失败

-非类型参数必须与相应的非类型模板参数的类型匹配,或者必须 可转换为14.3.2中规定的相应非类型参数的类型,否则 类型扣除失败

-指定的模板参数值将替换为相应的模板参数,如下所示: 指定如下

下面一段说:

执行此替换后,执行8.3.5中所述的功能参数类型调整。[…]

此外,第14.8.2/5段规定:

生成的替换和调整函数类型用作模板的函数模板类型 参数推导[…]

最后,第14.8.2/6段如下:

在模板参数推导过程中的某些点上,必须采用 使用模板参数并用相应的模板替换这些模板参数 参数。当任何显式指定的模板 参数被替换为函数类型,并再次替换为模板参数推导的末尾 替换从默认参数推导或获取的任何模板参数时

这一切似乎都意味着首先执行替换,然后执行模板参数推断。因此,在任何一种情况下都应该发生替换失败,并且应该从重载集中丢弃两个模板中的一个


不幸的是,似乎没有一个明确的规范来说明当模板参数被推导而不是显式指定时应该是什么行为。

这是否只适用于我们显式指定参数而不是推导参数的情况?(也就是说,如果我让函数取
T const&
,然后将
7
传递给它,那么这个把戏就不再合法了吗?@Yakk:在这种情况下,我不太确定,但我已经把整个14.8.2读了好几遍,在我看来,标准并没有规定行为应该是什么