【发布时间】:2016-02-08 18:22:00
【问题描述】:
我最近在这里问了一个问题 (Detecting instance method constexpr with SFINAE),我尝试在编译时进行一些 constexpr 检测。最终,我发现可以利用noexcept 来做到这一点:任何常量表达式也是noexcept。所以我把以下机器放在一起:
template <class T>
constexpr int maybe_noexcept(T && t) { return 0; }
...
constexpr bool b = noexcept(maybe_noexcept(int{}));
这行得通,b 如您所愿,因为零初始化 int 是一个常量表达式。它在应该的时候也正确地产生零(如果我将 int 更改为其他适当的类型)。
接下来,我想检查一下constexpr 是否可以移动构造。所以我这样做了:
constexpr bool b = noexcept(maybe_noexcept(int(int{})));
同样,这适用于int 或用户定义的类型。但是,这会检查该类型是否同时具有 constexpr 默认构造函数和 constexpr 移动构造函数。因此,为了解决这个问题,我尝试更改为 declval:
constexpr bool b = noexcept(maybe_noexcept(int(declval<int>())));
这导致b 在 gcc 5.3.0 中为假(不能使用 clang 来处理任何这些问题,因为 clang 不能正确地生成常量表达式 noexcept)。没问题,我说,一定是因为declval(很有趣)没有标记为constexpr。所以我写了我自己的幼稚版本:
template <class T>
constexpr T&& constexpr_declval() noexcept;
是的,与标准库的做法相比,这很幼稚,因为它会阻塞 void 和其他可能的东西,但现在还好。所以我再试一次:
constexpr bool b = noexcept(maybe_noexcept(int(constexpr_declval<int>())));
这仍然不起作用,b 总是错误的。为什么这不被视为常量表达式?这是编译器错误,还是我不了解constexpr 的基本知识? constexpr 和未评估的上下文之间似乎存在一些奇怪的交互。
【问题讨论】:
-
@Cameron 您所说的第二部分当然是正确的,但从技术上讲,第一部分不是。每个常量表达式是
noexcept,它可能不是。但是,constexpr函数的返回并不总是一个常量表达式。 -
你的函数调用不是常量表达式,因为它是未定义的 ([expr.const]/2.3)
标签: c++ c++11 template-meta-programming constexpr