SFINAE 不适用于 constexpr 函数?
SFINAE doesn't work on a constexpr function?
为了支持可移植性,我想根据size_t
是32位还是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();
由于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原则应用于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;
出于好奇,如果您想使用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{});
问题
SFINAE表示替换失败不是错误。
两个模板都不会在实例化过程中失败,相反,其中一个会在编译器查看它的时候失败(因为它会看到enable_ifs不依赖于模板参数,并尝试直接展开它们)。
解决方案解决方案是使检查依赖于一些模板参数,这样编译器只能在潜在的实例化时检查条件。 在您的情况下,最简单的解决方案是简单地提供一个默认模板参数,这是您想要检查的类型(下面的
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();
注意:另一种解决方案是将两个函数合并为一个函数,并使用三元运算符返回一个表达式的结果或另一个表达式的结果。
注意:既然检查依赖于模板参数,请确保您理解为什么需要使用
typename
来消除启用if的歧义。
相关文章:
- 条件constexpr函数
- constexpr 函数中的非文字(通过 std::is_constant_evaluated)
- constexpr构造函数需要常量成员函数时出现问题
- constexpr 函数获取常量字符*
- 如何在 constexpr 函数中实现回退运行时
- 为什么我不能在 constexpr lambda 函数中使用 std::tuple
- 在非 constexpr 函数中作为左值传递的变量上使用 'constexpr' 函数
- 在 constexpr 构造函数 (c++17) 中赋值到 const char * 在使用 Android NDK 时
- NVCC 错误:string_view.h:constexpr 函数返回是非常量
- constexpr函数中的静态constexpr变量
- 在 constexpr funnction 中调用basic_string函数
- 为什么我的 constexpr 对象在我的函数中不是 constexpr?
- constexpr log10 整数函数
- C++:初始化 constexpr 构造函数中的成员数组
- 编译器生成的默认构造函数具有 constexpr 混淆行为
- 在 constexpr 构造函数中初始化数组是否合法?
- 在 constexpr 函数中断言
- MSVC 和函数参数的 constexpr?
- 具有位域的结构的 Constexpr 构造函数
- C++ 默认构造函数 constexpr 或正确未定义