首页 文章

Constexpr decltype

提问于
浏览
5

我最近在这里问了一个问题(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 回答

  • 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 构造,并且......如果你没有 .

    你不能说“假装这个值是 constexpr 并告诉我一些表达式是否为 constexpr ” . 即使你可以,它也不能解决一般问题,因为如果表达式是 constexprconstexpr 参数的状态可能会改变!

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

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

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

相关问题