Yak*_*ont 8 c++ templates sfinae language-lawyer c++11
有一种技术我有时会在覆盖这样的template函数时使用:
#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>();
}
Run Code Online (Sandbox Code Playgroud)
此区分do_stuff从do_stuff,因为一个取0或多个UniqueEnum<1>S,而另一个取0或更多UniqueEnum<-1>秒.gcc 4.8认为这些不同的空包是不同的.
然而,在我尝试的最新版本的clang中,这失败了:它将0 UniqueEnum<1>s 的函数视为与0 s的函数相同UniqueEnum<-1>.
有一些简单的解决方法可以在clang中工作,但我想知道我的上述技术是否合法 - 做两个函数template,它们只有空的variardic参数包,实际上不同?
我认为 GCC 是对的,你的技术是正确的。基本上,由于 的类型参数C是明确指定的,问题是是否:
A。首先对函数模板签名中的其他位置进行替换C,然后执行类型推导(这应该会导致替换失败);或者
b. 首先进行类型推导,然后进行替换(这不会导致替换失败,因为相应的参数包将为空,因此不会执行替换)。
\n\n看来 GCC 假设 (1),而 Clang 假设 (2)。C++11 标准第 14.8.2/2 段规定:
\n\n\n\n\n当指定显式模板参数列表时,模板参数必须与\n 模板参数列表兼容,并且必须产生有效的函数类型,如下所述;否则类型推导失败。具体来说,在评估与给定函数模板相关的显式指定模板参数列表时,将执行以下步骤:
\n\n\xe2\x80\x94 指定的模板实参必须与模板形参类型相匹配(即类型、非类型、\n 模板)。参数的数量不得多于参数的数量,除非至少有一个参数是模板参数包,并且每个非参数包都应有一个参数。否则,\n 类型推导将失败。
\n\n\xe2\x80\x94 非类型参数必须与相应非类型模板参数的类型匹配,或者必须\n 可转换为 14.3.2 中指定的相应非类型参数的类型,否则\n 类型扣除失败。
\n\n\xe2\x80\x94指定的模板参数值将替换下面指定的相应模板参数。
\n
下面的段落接着说:
\n\n\n\n\n执行此替换后,将执行 8.3.5 中描述的功能参数类型调整。[...]
\n
此外,第 14.8.2/5 段规定:
\n\n\n\n\n替换和调整后的函数类型用作 template\n 参数推导的函数模板类型。[...]
\n
最后,第 14.8.2/6 段如下:
\n\n\n\n\n在模板参数推导过程中的某些时刻,需要采用使用模板参数的函数类型,并将这些模板参数替换为相应的模板参数。当任何显式指定的模板参数被替换为函数类型时,在模板参数推导开始时执行此操作;当从默认参数推导或获得的任何模板参数被替换时,在模板参数推导结束时再次执行此操作。
\n
这一切似乎都意味着首先执行替换,然后执行模板参数推导。因此,在任何一种情况下都应该发生替换失败,并且应该从重载集中丢弃两个模板之一。
\n\n不幸的是,似乎没有明确的规范来说明当模板参数被推导而不是被显式指定时应该是什么行为。
\n| 归档时间: |
|
| 查看次数: |
248 次 |
| 最近记录: |