Constexpr decltype

时间:2016-02-08 18:22:00

标签: c++ c++11 template-meta-programming constexpr

我最近在这里问了一个问题(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中为false(不能使用clang进行任何此操作,因为clang不能正确地生成常量表达式noexcept)。我说,没问题,因为declval(有趣的是)没有标记constexpr。所以我写了自己的天真版本:

template <class T>
constexpr T&& constexpr_declval() noexcept;

是的,与标准库的工作方式相比,这是天真的,因为它会阻塞虚空和可能的其他东西,但它现在很好。所以我再试一次:

constexpr bool b = noexcept(maybe_noexcept(int(constexpr_declval<int>())));

这仍然不起作用,b始终为假。为什么这不被视为常数表达式?这是编译器错误,还是我不了解constexpr的基本原理?似乎constexpr和未评估的上下文之间存在一些奇怪的交互。

1 个答案:

答案 0 :(得分:6)

必须定义

constexpr个表达式。您的定义未定义,因此int(constexpr_declval<int>())不是constexpr

这意味着maybe_noexcept(int(constexpr_declval<int>()))不是constexpr,因此不是noexcept

编译器正确返回false

您也无法在constexpr中调用UB。

我想不出对constexpr引用任意数据的方法。我认为对齐存储的constexpr缓冲区被重新解释为对数据类型的引用,但在许多上下文中都是UB,因此不是 - constexpr

一般来说,这是不可能的。想象一下,你有一个类,其状态决定了方法调用是constexpr

struct bob {
  int alice;
  constexpr bob(int a=0):alice(a) {}
  constexpr int get() const {
    if (alice > 0) throw std::string("nope");
    return alice;
  }
};

现在,bob::get constexpr是不是?如果您使用非正面constexpr bob构建alice,并且......如果没有,则不会。

您不能说&#34;假装此值为constexpr并告诉我某些表达式是否为constexpr&#34;。即使你可以,它也不会解决这个问题,因为如果表达式是constexprconstexpr参数的状态可能会改变! / p>

更有趣的是,bob().get() 是constexpr ,而bob(1).get()则不是。因此,您的第一次尝试(默认构造类型)甚至给出了错误的答案:您可以测试,然后执行操作,操作将失败。

对象实际上是方法的参数,如果没有al参数的状态,则无法确定函数是否为constexpr

确定表达式是否为constexpr的方法是在constexpr上下文中运行它并查看它是否有效。