接合模板不会短路

时间:2019-07-13 11:41:45

标签: c++ templates c++17 short-circuiting

我希望能够评估一个函数是否接受一个int类型的参数,以及它是否返回void。为此,我使用了std::conjunction,因为我认为它应该短路并且不评估第二个格式错误的表达式,以防该函数无法使用int类型的一个参数进行调用,但是由于某种原因,我得到了一个编译器错误:

#include <iostream>
#include <type_traits>
template<typename Function>
struct oneArgVoid
{
    static constexpr bool value = std::conjunction_v<std::is_invocable<Function, int>, std::is_void<std::invoke_result_t<Function, int>>>;
};

int main()
{
    auto l1 = [](auto x) {};
    std::cout << oneArgVoid<decltype(l1)>::value << "\n";
    auto l2 = [](auto x) {return 1; };
    std::cout << oneArgVoid<decltype(l2)>::value << "\n";
    auto l3 = [](auto x, auto y) {};
    std::cout << oneArgVoid<decltype(l3)>::value << "\n";
    return 0;
}

请注意,如果未在oneArgVoid上调用l3,则会编译代码。现场演示:https://godbolt.org/z/8BUfpT

我不使用升压,所以不能使用mpl::eval_if。但是我认为std::conjunction应该在这里短路,对吗?

考虑到HolyBlackCat的建议,这甚至是一个陌生人:https://godbolt.org/z/2SUij-

1 个答案:

答案 0 :(得分:1)

似乎std::conjunction仅在类型的值上短路,类型本身仍然必须结构良好。因此,这:std::is_void<std::invoke_result_t<Function, int>>实际上在这里是非法的。由于进行了修改:

template<typename Function>
struct argVoid
{
    static constexpr bool value = std::is_void_v<std::invoke_result_t<Function, int>>;
};

template<typename Function>
struct oneArgVoid
{
    static constexpr bool value = std::conjunction_v<std::is_invocable<Function, int>, argVoid<Function>>;
};

它有效,因为格式错误的表达式现在位于value变量中,这意味着由于短路而无法进行评估。