检查是否可以计算 lambda constexpr (C++17)

问题描述 投票:0回答:1

我正在尝试找到一种方法来检查 lambda 是否可以不断评估或 不在 C++17 中。假设我要检查的 lambda 不带 参数。

我偶然发现 这个 问题,其接受的答案如下所示:

template <class Lambda, int = (Lambda{}(), 0)>
constexpr std::true_type is_cx_invocable(Lambda) {
    return {};
}

constexpr std::false_type is_cx_invocable(...) {
    return {};
}

其中存在以下问题:

  1. 它只适用于 C++20(因为默认需要无捕获的 lambda 可构造),我正在寻找 C++17 解决方案;

  2. 如果

    is_cx_invocable
    返回
    false
    ,不清楚是不是问题
    Lambda
    不是默认可构造的或其调用运算符不是
    constexpr
    ,例如:

int main() {
    static_assert(is_cx_invocable([] { return 0; }));

    int i{};
    auto cxLambda = [i] { return 0; };
    (std::array<int, cxLambda()>{}, (void)0);
    //               ^ cxLambda is indeed constexpr invocable
    //                 (but not default constructible)

    auto isCxLambdaCx = is_cx_invocable(cxLambda);
    static_assert(!isCxLambdaCx);  // This fails
}

所以,我尝试了这个:

template <class Lambda>
constexpr auto is_cx_invocable(Lambda lambda)
    -> std::integral_constant<bool, (lambda(), 1)> { // or
    //-> std::enable_if_t<(lambda(), 1), std::true_type> {
    return {};
}

constexpr std::false_type is_cx_invocable(...) {
    return {};
}

哪个:

  1. 不需要 C++20 特性;

  2. 修复上面的问题(2):

int main() {
    int i{};
    auto cxLambda = [i] { return 0; };
    auto isCxLambdaCx = is_cx_invocable(cxLambda);
    static_assert(isCxLambdaCx); // OK now
}

问题是这个解决方案可以很好地与 Clang 和 MSVC 编译,但失败了 在 GCC 上编译。 在这里你是一个编译器 explorer链接玩。

我的问题是:

  1. 我的解决方案是否格式错误(因此 GCC 拒绝我的代码是正确的)?

  2. 是否有一个可移植的(即可以用 ISO C++ 实现并且独立于 编译器怪癖)来实现 C++17 中的

    is_cx_invocable
    检查?

c++ gcc c++17 constexpr template-meta-programming
1个回答
0
投票

有一条规则,函数参数不应被同一函数的默认参数潜在地评估:[dcl.fct.default]/9.

不过,好像GCC太严格了。它似乎在强制执行一条规则,即在主体开始之前不得评估函数参数(即您不能在尾随返回类型中执行此操作)。

所以我认为 Clang 和 MSVC 在这里是正确的。事实上,标准中没有任何规则会导致此示例格式错误。

(我也撤回了我原来答案的后半部分,因为这似乎是由于我的误解。您描述的元编程技术应该有效。)

© www.soinside.com 2019 - 2024. All rights reserved.