mkm*_*afa 14 c++ templates c++11
代码示例1:
namespace detail {
enum enabler { dummy };
}
class foo {
public:
template <typename T,
typename std::enable_if<!std::is_integral<T>::value,
detail::enabler>::type = detail::enabler::dummy>
void func(T t) {
std::cout << "other" << std::endl;
}
template <typename T,
typename std::enable_if<std::is_integral<T>::value,
detail::enabler>::type = detail::enabler::dummy>
void func(T t) {
std::cout << "integral" << std::endl;
}
};
Run Code Online (Sandbox Code Playgroud)
代码示例2:
namespace detail {
enum enabler { dummy };
}
class foo {
public:
template <typename T,
typename T2 = typename std::enable_if<!std::is_integral<T>::value, detail::enabler>::type>
void func(T t) {
std::cout << "other" << std::endl;
}
template <typename T,
typename T2 = typename std::enable_if<std::is_integral<T>::value, detail::enabler>::type>
void func(T t) {
std::cout << "integral" << std::endl;
}
};
Run Code Online (Sandbox Code Playgroud)
我理解为什么样本2不能编译.基本上,因为这两个模板函数像彼此(它们甚至具有相同的模板的参数T,T2).
我不明白为什么样本1编译!我看到这是同样的问题.基本上不是将第二个模板参数作为a typename,而是一次enum而不是typename这次.
有人可以解释一下吗?
此外,我执行了以下代码,它返回true,这更令人困惑!(理解它是真的但是混淆样本1编译)
std::cout
<< std::boolalpha
<< std::is_same<std::enable_if<std::is_integral<int>::value, int>::type,
std::enable_if<!std::is_integral<float>::value, int>::type>::value
<< std::endl;
Run Code Online (Sandbox Code Playgroud)
默认参数(默认函数参数或默认模板参数)不是函数签名的一部分.您只能使用给定签名定义一个函数.
在代码示例1中,如果我们删除参数的名称和所有默认值,我们有两个函数:
template <typename T, std::enable_if_t<!std::is_integral<T>::value, detail::enabler>>
void func(T ) { ... }
template <typename T, std::enable_if_t<std::is_integral<T>::value, detail::enabler>>
void func(T ) { ... }
Run Code Online (Sandbox Code Playgroud)
这是两个不同的签名 - 第二个模板参数在两个函数中都有不同的类型 - 所以它从这个角度来看是有效的.
现在,当我们实际调用它时会发生什么.如果T是整数类型,则在两种情况下都会替换第二个参数:
template <typename T, ????> void func(T ) { ... }
template <typename T, detail::enabler = dummy> void func(T ) { ... }
Run Code Online (Sandbox Code Playgroud)
在第一个函数中,表达式typename std::enable_if<false, detail::enabler>::type是不正确的.type该类型没有typedef.通常,编写不正确的代码是一个硬编译器错误.但是,由于一个名为SFINAE的规则(替换失败不是错误),在模板替换的直接上下文中出现的格式错误的代码不是错误 - 它只会导致从考虑集中删除函数/类模板特化.所以我们最终只有一个有效的:
template <typename T, detail::enabler = dummy> void func(T ) { ... }
Run Code Online (Sandbox Code Playgroud)
被调用.
但是,在代码示例2中,我们有以下两个函数:
template <typename T, typename>
void func(T ) { ... }
template <typename T, typename>
void func(T ) { ... }
Run Code Online (Sandbox Code Playgroud)
那些是一样的!我们两次定义相同的函数 - 这是不允许的,因此错误.出于同样的原因,这是一个错误:
int foo(int x = 1) { return x; }
int foo(int x = 2) { return x; }
Run Code Online (Sandbox Code Playgroud)
是一个错误.
这就是为什么Xeo使用(不可构造的)枚举来启用如果开始 - 它使得更容易编写不相交的函数模板特化,因为你可以使用枚举,但你不能用类型.
请注意,您可以类似地执行相同的操作,例如int:
template <class T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
void func(T ) { ... }
Run Code Online (Sandbox Code Playgroud)
但这将允许邪恶的用户为该参数提供一个值(在这个特定的上下文中无关紧要,但在其他情况下也可以).有detail::enabler,没有提供这样的价值.
| 归档时间: |
|
| 查看次数: |
739 次 |
| 最近记录: |