class 默认值的模板参数
template parameter with default value for class
我不太明白下面的代码,模板有两个参数,第二个有class = xxxx
,这让我觉得很奇怪。你能给我解释一下我应该怎么理解吗?除了 std::enable_if
,这个 c++ feature 是否还有其他用例?
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even (T i) {return !bool(i%2);}
一个字:SFINAE.
替换失败不是错误。
用google寻找那个词,一个全新的世界将为你打开。
让我们看看你的代码的意思。
std::is_integral<typename T>::value
这是一个布尔值,依赖于类型 T
,如果 T
是整数类型,则值为 true
,否则为 false
。
std::enable_if<bool B, typename T = void>::type
它是类型 T
,当 B == true
时,没有别的。
因此,在您的代码中
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
当 T
是一个整数类型时,第二个(未命名的)模板参数被替换为一个类型(默认值:void
;但是,在这种情况下,确切的类型是无关紧要的)并且功能被激活。相反,当 T
不是整数类型时,第二个模板参数的替换失败并且此版本的 is_even()
函数未激活(对于类型 T
) 而且,这是重点,它不是错误(可以激活另一个版本的 is_even()
)。
更有趣的是如何为非整数类型实现 is_even()
的替代版本。你可以认为你可以实现另一个否定 std::is_integral
的版本
template < class T,
class = typename std::enable_if<false == std::is_integral<T>::value>::type>
但这不起作用(是一个错误并且无法编译),因为您有两个 is_even()
模板函数,它们(从模板参数的角度来看)仅在默认参数方面有所不同。
解决方案可以将 SFINAE 应用于 return 值
#include <type_traits>
#include <iostream>
template <typename T>
typename std::enable_if<true == std::is_integral<T>::value, bool>::type
is_even (T const & i)
{ return ! (i%2); }
template <typename T>
typename std::enable_if<false == std::is_integral<T>::value, bool>::type
is_even (T const &)
{ return false; }
int main()
{
std::cout << "-- is 7 even ? " << is_even(7) << '\n';
std::cout << "-- is 8UL even ? " << is_even(8LL) << '\n';
std::cout << "-- is \"abc\" even ? " << is_even("abc") << '\n';
return 0;
}
通过这种方式,您可以为整数类型启用 is_even()
版本,为非整数类型启用第二个版本(return 甚至 false
)。
p.s.: 对不起我的英语不好
我不太明白下面的代码,模板有两个参数,第二个有class = xxxx
,这让我觉得很奇怪。你能给我解释一下我应该怎么理解吗?除了 std::enable_if
,这个 c++ feature 是否还有其他用例?
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even (T i) {return !bool(i%2);}
一个字:SFINAE.
替换失败不是错误。
用google寻找那个词,一个全新的世界将为你打开。
让我们看看你的代码的意思。
std::is_integral<typename T>::value
这是一个布尔值,依赖于类型 T
,如果 T
是整数类型,则值为 true
,否则为 false
。
std::enable_if<bool B, typename T = void>::type
它是类型 T
,当 B == true
时,没有别的。
因此,在您的代码中
template < class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
当 T
是一个整数类型时,第二个(未命名的)模板参数被替换为一个类型(默认值:void
;但是,在这种情况下,确切的类型是无关紧要的)并且功能被激活。相反,当 T
不是整数类型时,第二个模板参数的替换失败并且此版本的 is_even()
函数未激活(对于类型 T
) 而且,这是重点,它不是错误(可以激活另一个版本的 is_even()
)。
更有趣的是如何为非整数类型实现 is_even()
的替代版本。你可以认为你可以实现另一个否定 std::is_integral
template < class T,
class = typename std::enable_if<false == std::is_integral<T>::value>::type>
但这不起作用(是一个错误并且无法编译),因为您有两个 is_even()
模板函数,它们(从模板参数的角度来看)仅在默认参数方面有所不同。
解决方案可以将 SFINAE 应用于 return 值
#include <type_traits>
#include <iostream>
template <typename T>
typename std::enable_if<true == std::is_integral<T>::value, bool>::type
is_even (T const & i)
{ return ! (i%2); }
template <typename T>
typename std::enable_if<false == std::is_integral<T>::value, bool>::type
is_even (T const &)
{ return false; }
int main()
{
std::cout << "-- is 7 even ? " << is_even(7) << '\n';
std::cout << "-- is 8UL even ? " << is_even(8LL) << '\n';
std::cout << "-- is \"abc\" even ? " << is_even("abc") << '\n';
return 0;
}
通过这种方式,您可以为整数类型启用 is_even()
版本,为非整数类型启用第二个版本(return 甚至 false
)。
p.s.: 对不起我的英语不好