Via*_*lov 5 c++ templates enable-if constexpr c++11
为了支持可移植性,我想根据size_t32位或64位的事实选择一个常量.代码:
using namespace std;
namespace detail {
template<enable_if<is_same<size_t, uint32_t>::value,void*>::type = nullptr>
constexpr static const size_t defaultSizeHelper() {
return ( (size_t) 1 << 30 ) / 2 * 5; //2,5 Gb
}
template<enable_if<is_same<size_t, uint64_t>::value,void*>::type = nullptr>
constexpr size_t defaultSizeHelper() {
return numeric_limits<size_t>::max() / 2;
}
}
constexpr static size_t defaultSize = detail::defaultSizeHelper();
Run Code Online (Sandbox Code Playgroud)
由于这个代码不能编译 error: 'std::enable_if<false, void*>::type' has not been declared. template<enable_if<is_same<size_t, uint64_t>::value,void*>::type = nullptr>
编译器 - GCC 4.9
在我看来,编译器不会将SFINAE原则应用于a constexpr.那我该怎么办?
SFINAE背后的原理是,如果推断的模板参数的替换导致格式错误的代码,那么该函数模板将从重载分辨率集中删除,而不是导致硬错误.
在您的情况下,没有推断的模板参数或替换一个,因此您最终会出现编译错误.所有你需要的是
constexpr static size_t defaultSize = is_same<size_t, uint32_t>::value
? (( (size_t) 1 << 30 ) / 2 * 5)
: numeric_limits<size_t>::max() / 2;
Run Code Online (Sandbox Code Playgroud)
出于好奇,如果你想使用SFINAE,你可以做这样的事情
namespace detail {
template<typename T, typename enable_if<is_same<T, uint32_t>::value,void*>::type = nullptr>
constexpr static const T defaultSizeHelper(T) {
return ( (size_t) 1 << 30 ) / 2 * 5; //2,5 Gb
}
template<typename T, typename enable_if<is_same<T, uint64_t>::value,void*>::type = nullptr>
constexpr T defaultSizeHelper(T) {
return numeric_limits<size_t>::max() / 2;
}
}
constexpr static size_t defaultSize = detail::defaultSizeHelper(size_t{});
Run Code Online (Sandbox Code Playgroud)
SFINAE代表替换失败不是错误。
您的两个模板在实例化过程中都不会失败,相反,其中一个模板会在编译器查看它时失败(因为它会发现enable_if不依赖于模板参数,并尝试直接扩展它们)。
解决方案是使检查依赖于某些模板参数,以便编译器只能在潜在实例化时检查条件。
在您的情况下,最简单的解决方案是简单地提供一个默认模板参数,该参数是您想要检查的类型(T如下所示)。
using namespace std;
namespace detail {
template<class T = uint32_t, typename enable_if<is_same<size_t, T>::value,void*>::type = nullptr>
constexpr static const size_t defaultSizeHelper() {
return ( (size_t) 1 << 30 ) / 2 * 5; //2,5 Gb
}
template<class T = uint64_t, typename enable_if<is_same<size_t, T>::value,void*>::type = nullptr>
constexpr size_t defaultSizeHelper() {
return numeric_limits<size_t>::max() / 2;
}
}
constexpr static size_t defaultSize = detail::defaultSizeHelper();
Run Code Online (Sandbox Code Playgroud)
注意:另一种解决方案是将两个函数合并为一个,并使用三元运算符返回一个表达式的结果或另一个表达式的结果。。
注意:既然检查依赖于模板参数,请确保您理解为什么需要使用
typename来消除启用 if 的歧义。请参阅此答案以获取更多信息。