is_constexpr在C ++ 11中可能吗?

是否有可能根据C ++ 11expression式是否是C ++ 11中的常量expression式(即constexpr )来生成编译时布尔值? 关于这个问题的几个问题与此有关,但我没有在任何地方看到明确的答案。

我曾经写过(编辑:见下面的限制和解释)。 从https://stackoverflow.com/a/10287598/34509

 template<typename T> constexpr typename remove_reference<T>::type makeprval(T && t) { return t; } #define isprvalconstexpr(e) noexcept(makeprval(e)) 

但是常量expression式有很多种。 上面的答案检测prvalue常量expression式。


说明

noexcept(e)expression式给出了false如果包含

  • 除非调用是一个常量expression式,否则对一个没有非抛出exception规范的函数进行潜在的计算调用,
  • 一个潜在的评估throwexpression,
  • 一个潜在评估的dynamic_casttypeid抛出的forms。

请注意,函数模板makeprval没有被声明为noexcept ,所以调用需要是第一个项目符号不适用的常量expression式,这就是我们所滥用的。 我们需要其他子弹不适用,但值得庆幸的是,在常量expression式中不允许使用throw和throwable dynamic_casttypeid ,所以这很好。

限制

不幸的是有一个可以或不重要的限制。 “潜在评估”的概念比常数expression式适用的限制要保守得多。 所以上面的noexcept可能会给出错误的否定。 它会报告一些expression式不是常数expression式,尽pipe它们是。 例:

 constexpr int a = (0 ? throw "fooled!" : 42); constexpr bool atest = isprvalconstexpr((0 ? throw "fooled!" : 42)); 

在上面的atest是假的,即使初始化成功了。 这是因为作为一个常量expression式,“邪恶的”非常量子expression式是“永远不会被评估”的,尽pipe这些邪恶的子expression式是可以被正式评估的。

这是一个尝试,当然它只适用于现在的function(欢迎任何批评):

 #include <type_traits> #include <iostream> template<typename T> constexpr bool wrapper(T){ return true; } template <typename F, typename std::decay<F>::type FP, typename... Args, bool = wrapper(FP(Args{}...))> constexpr bool is_constexpr_impl(bool&&) { return true; } template <typename F, typename std::decay<F>::type FP, typename... Args> constexpr bool is_constexpr_impl(const bool&&) { return false; } template <typename F, typename std::decay<F>::type FP, typename... Args> constexpr bool is_constexpr(Args...) { return is_constexpr_impl<F, FP, Args...>(0); } constexpr int f(int a, int b) { return a + b; } constexpr float g(float a, float b) { return a + b; } int h(int a, int b) { return a + b; } float i(float a, float b) { return a + b; } int main() { std::cout << std::boolalpha; std::cout << is_constexpr<decltype(f), &f>(1, 1) << std::endl; std::cout << is_constexpr<decltype(g), &g>(1.0f, 1.0f) << std::endl; std::cout << is_constexpr<decltype(h), &h>(1, 1) << std::endl; std::cout << is_constexpr<decltype(i), &i>(1.0f, 1.0f) << std::endl; } 

liveworkspace上的示例 。

让我们用SFINAE成语做一些天真的玩法:

 template <typename C> struct IsConstExpr { typedef char yes; typedef char no[2]; template <typename T> static constexpr yes& swallow(T) { int x[T()]; return 0; }; template <typename T> static no& swallow(...); static const int value = sizeof(swallow<C>(0)) == sizeof(yes); }; 

上面的代码在语法上是错误的,但它会给我们一些见解。 我们试着利用它:

 constexpr int f() { return 32167; } int g() { return 32167; } int main() { std::cout << IsConstExpr<decltype(&f)>::value << std::endl; } 

编译器说:

 In instantiation of 'static constexpr IsConstExpr<C>::yes& IsConstExpr<C>::swallow(T) [with T = int (*)(); C = int (*)(); IsConstExpr<C>: :yes = char]': 

现在问题是显而易见的:模板的参数是T = int (*)();

这意味着constexpr 不是types的一部分, 我们无法检测到它