如何让编译器忽略这个计算结果为 false 的 if-constexpr?

Par*_*son 3 c++ c++17 if-constexpr

我正在编写一个宏,当用于包装像这样的函数调用时:macro(function())返回 a std::optional<T>,其中 T 是函数的返回值。到目前为止它可以工作,但是std::optional<bool>当函数没有返回类型(即它返回void)时,我试图让它返回a时遇到了问题。

问题的核心是编译器尝试评估 if-constexpr 的范围,当函数没有返回类型时,该 if-constexpr 的计算结果为 false。

我尝试使用两个 if-constexpr 和一个 else。我尝试内联所有内容并将其展开几行。我尝试用常量文字替换编译器计算的 constexpr 常量。到目前为止没有任何效果。

我现在拥有的宏如下所示:

#ifndef troy
#define troy(body)[](){\
    constexpr auto inner_type_is_void=std::is_same<decltype(body), void>::value;\
    using inner_type=std::conditional<inner_type_is_void,bool,decltype(body)>::type;\
    try{\
        if constexpr (inner_type_is_void) {(body); return std::optional<inner_type>{true};}\
        if constexpr (!inner_type_is_void) {return std::optional<inner_type>{(body)};}\
    } catch (...){\
        return std::optional<inner_type>{};\
    }\
}()
#endif
Run Code Online (Sandbox Code Playgroud)

我像这样使用它:

{
    auto a=troy(f());
    if (!a){
        std::cout << "fail" << std::endl;
    } else{
        std::cout << "success: " << *a << std::endl;
    }
}

Run Code Online (Sandbox Code Playgroud)

它在 f 返回一个值时工作,但在不返回时给出编译器错误。此编译器错误是:no matching function for call to ‘std::optional<bool>::optional(<brace-enclosed initializer list>)’在 if-constexpr 评估为 false 的行上。

Bar*_*rry 5

为了避免对 进行实例化if constexpr,您需要一个实际具有实例化的上下文:您需要某种模板。在模板之外,没有if constexpr赋予的魔力。

与往常一样,解决方案是将所有内容都包装在 lambda 中。现在,您正在将body内联用于实际的函数体。相反,您可以使用 lambda:

[&]() -> decltype(auto) { return body; }
Run Code Online (Sandbox Code Playgroud)

然后将整个事情包装在一个立即调用的 lambda 中,该 lambda 将这个 lambda 作为参数:

[](auto f){
    // stuff
}([&]() -> decltype(auto) { return body; })
Run Code Online (Sandbox Code Playgroud)

现在,在我标记的地方// stuff,我们处于模板上下文中,我们实际上可以使用它if constexpr来避免实例化:

[](auto f){
    using F = decltype(f);
    using R = std::invoke_result_t<F>;
    try {
        if constexpr (std::is_void_v<R>>) {
            f();
            return std::optional<bool>(true);
        } else {
            return std::make_optional(f());
        }
    } catch (...) {
        return std::optional<std::conditional_t<std::is_void_v<R>, bool, R>>();
    }
}([&]() -> decltype(auto) { return body; })
Run Code Online (Sandbox Code Playgroud)

现在只需添加一堆\s 就可以了。