【发布时间】:2016-08-26 10:09:48
【问题描述】:
这是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!为了检查由于某种原因错误重载并不总是被调用,我注释掉了错误重载并得到编译器错误:
注意:候选模板被忽略:替换失败 [with N = 0, T = const std ::tuple]:非类型模板参数不是常量表达式
自动检查(const T& arg) -> sfinae_true;
但是,我知道我可以调用 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 函数参数的规则是什么?
【问题讨论】:
-
问题是
arg参数不是constexpr... -
(稍微扩展一下我认为@Jarod42 的含义:
arg作为函数参数永远不会被视为常量表达式,即使您提供给函数的参数是常量表达式。) -
如果此方法不起作用,我将如何检测函数调用的结果是否为 constexpr?显然,我可以通过构造
a_val对象将元组用作 constexpr 值。 -
@helloworld922:
constexpr int f(const std::tuple<int>& t) {A<std::get<0>(t)> a_val; return 0;}不起作用。
标签: c++ c++14 constexpr sfinae