我一直在努力理解C ++选择模板的方式。即,请考虑以下代码示例:
template <typename R>
class Curious
{
public:
template <typename T, typename std::enable_if<std::is_const<T>::value, int>::type = 33>
void test1() {}
template <typename T, typename std::enable_if<!std::is_const<T>::value, int>::type = 33>
void test1() {}
template <typename T, typename = typename std::enable_if<std::is_const<T>::value>::type>
void test2() {}
template <typename T, typename = typename std::enable_if<!std::is_const<T>::value>::type>
void test2() {}
template <typename std::enable_if<std::is_const<R>::value>::type * = nullptr>
void test3() {}
template <typename std::enable_if<!std::is_const<R>::value>::type * = nullptr>
void test3() {}
// works
template <typename T = void>
typename std::enable_if<std::is_const<R>::value, T>::type test4() {}
template <typename T = void>
typename std::enable_if<!std::is_const<R>::value, T>::type test4() {}
// also works
template <typename T = void, typename std::enable_if<std::is_const<R>::value, T>::type * = nullptr>
void test5() {}
template <typename T = void, typename std::enable_if<!std::is_const<R>::value, T>::type * = nullptr>
void test5() {}
}; // Curious
前两个函数(test1)工作正常(为什么?):
Curious<int> curious;
curious.test1<int>();
curious.test1<const int>();
其余部分导致编译错误。 关于函数test2,编译器声称我正在尝试创建副本:
error C2535: 'void Curious::test2(void)': member function already defined or declared
Here文档说:
一个常见的错误是声明两个不同的函数模板 在他们的默认模板参数中。这是违法的,因为默认 模板参数不是函数模板签名的一部分,而且 声明具有相同签名的两个不同的函数模板是 非法的。
所以情况似乎如此。但是,我没有看到与前两个函数有太大区别,前两个函数也有默认的模板参数。因此,我们对默认值(test1 - works)有一个默认类型(test2 - 不起作用)。关于它有什么规则吗?
如果是test3:
error C2039: 'type': is not a member of 'std::enable_if'与第一种情况一样,这次成员函数模板具有默认的非类型参数,但它取决于类模板参数。现在SFINAE没有跳过错误的(也不知道为什么)。
在第四种情况下,SFINAE通过返回类型解析模板。但这些test4函数是否具有相同的签名?因为它们仅在返回类型上有所不同。
据我了解,在第五种情况下,添加额外参数会使test5签名依赖于函数模板参数,因此SFINAE会启动并解析它。
我对C ++如何处理这些模板感到很困惑。有人可以这么清楚这些事吗?
答案 0 :(得分:9)
删除默认值后,对于test1,您有:
template <typename T, typename std::enable_if<std::is_const<T>::value, int>::type>
void test1();
template <typename T, typename std::enable_if<!std::is_const<T>::value, int>::type>
void test1();
其中有明显不同的签名。
对于test2:
template <typename T, typename> void test2();
template <typename T, typename> void test2();
明显相同的签名。
对于test3,SFINAE无法应用,因为您遇到了严重错误,因为R
已在课程中修复,而enable_if
并不依赖于模板参数功能
对于test4,模板函数的签名有一个例外,因为重载可能只有返回类型不同所以
int foo();
char foo(); // Illegal.
但
template <typename T> int foo();
template <typename T> char foo(); // legal, even it is not trivial to call
此外,std::enable_if<!std::is_const<R>::value, T>::type
取决于模板参数T
,所以没关系。
对于test5,第二个模板参数取决于第一个模板参数T
,所以它也可以。