这是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&amp; arg) - &gt; sfinae_true≤(标准::得到(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;
}
编译得很好。
我在Ubuntu 16.04上使用Clang 3.8.0进行了测试。
修改
作为基于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函数参数的规则是什么?
答案 0 :(得分:3)
这看起来像编译器问题。
template<size_t N, class T>
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>;
gcc无法编译:
t.C:8:61:错误:模板参数1无效自动检查(const T&amp; arg) - &gt; sfinae_true≤(标准::得到(ARG),N)取代;
但稍微调整一下后,我用gcc 6.1.1得到了预期的结果:
#include <tuple>
#include <type_traits>
#include <iostream>
template<size_t> struct sfinae_true : std::true_type{};
template<size_t N, class T>
auto check(const T& arg)
{
return 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';
}
这导致:
is constexpr? 1
请注意,在C ++ 11之前的常量表达式中不允许使用逗号。可能是那个时代留下的东西......