这是Detecting constexpr with SFINAE的后续问题 .
我想检测元组的元素(或任何可与 std::get
一起使用的元素)是否为constexpr . 所以我编写了以下助手,类似于Xeo给出的:
template<size_t> struct sfinae_true : std::true_type{};
template<size_t N, class T>
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>;
template<size_t N, class>
std::false_type check(...);
现在我的测试驱动代码:
int main()
{
constexpr std::tuple<size_t, size_t> arg(4,5);
typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr;
std::cout << "is constexpr? " << is_cexpr::value << '\n';
}
但是,这总是为我打印 false
!要检查由于某种原因,并不总是调用错误的重载,我注释掉了错误的重载并得到编译器错误:
注意:候选模板被忽略:替换失败[有N = 0,T = const std :: tuple]:非类型模板参数不是常量表达式自动检查(const T&arg) - > sfinae_true <(std :: get (ARG),0)>;
但是,我知道我可以调用 std::get<N>(arg)
并获得constexpr值:
template<size_t N>
class A{};
int main()
{
constexpr std::tuple<size_t, size_t> arg(4,5);
A<std::get<0>(arg)> a_val;
}
编译得很好 .
-
为什么检查功能无法正确检测到constexpr-ness?
-
如何解决这个问题?
我在Ubuntu 16.04上使用Clang 3.8.0对此进行了测试 .
edit:
作为基于Sam的回答的进一步测试,我尝试了以下形式:
template<size_t N, class T>
auto check(const T& arg)
{
return sfinae_true<(std::get<N>(arg)*0)>();
}
这完全摆脱了逗号运算符,GCC 5.4.0编译得很好,但Clang 3.8.0仍然抱怨 . 有趣的是,Clang强调 arg
本身不是constexpr .
为什么这个问题仍然存在? constexpr函数参数的规则是什么?
1 回答
这看起来像编译器问题 .
gcc无法编译:
但经过稍微调整后,我得到了gcc 6.1.1的预期结果:
这导致:
请注意,在C 11之前的常量表达式中不允许使用逗号 . 可能是那个时代遗留下来的东西......