基于Lambda Arity的专业化功能模板

lig*_*ulb 6 c++ lambda templates arity c++17

我正在尝试根据作为参数传递给它的lambda的优缺点来专门化模板化函数。这是我想出的解决方案:

template<typename Function, bool>
struct helper;

template<typename Function>
struct helper<Function, false>
{
    auto operator()(Function&& func)
    {
        std::cout << "Called 2 argument version.\n";
        return func(1, 2);
    }
};

template<typename Function>
struct helper<Function, true>
{
    auto operator()(Function&& func)
    {
        std::cout << "Called 3 argument version.\n";
        return func(1, 2, 3);
    }
};

template<typename T>
struct B
{
    T a;
    const T someVal() const { return a; }
};

template<typename Function, typename T>
auto higherOrderFun(Function&& func, const T& a)
{
    return helper<Function, std::is_invocable<Function, decltype(a.someVal()), decltype(a.someVal()), decltype(a.someVal())>::value>{}(std::forward<Function>(func));
}


int main()
{
    B<int> b;
    std::cout << higherOrderFun([](auto x, auto y) {return x+y; }, b) << "\n";
    std::cout << higherOrderFun([](auto x, auto y, auto z) {return x + y+z; }, b) << "\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

有没有办法以更优雅的方式实现这一目标?我已经看过了:通用lambda的Arity

但是,最新的解决方案(florestan's)将所有参数都转换为aribtrary_t,因此必须将它们强制转换回每个lambda内,我觉得不太理想。理想情况下,我希望直接对higherOrderFun使用SFINAE 的模板进行专业化处理,但是因为它是我使用帮助器类来实现的。还有更简单的方法吗?例如直接应用SFINAE higherOrderFun而不依赖helper类?这样做的全部目的是不必更改higherOrderFunhigherOrderFun2higherOrderFun3,而是让编译器根据lambda和给定的参数(const T& a)推断出正确的专业化。

我要指出,我也不在乎的函数的自变量的类型-只是他们算的,所以我就改decltype(a.someVal())auto在我的例子,如果这是可能的(也许有办法来规避明确定义的类型? )。

Jar*_*d42 2

我会使用不同的重载:

template<typename Function>
auto higherOrderFun(Function&& func)
-> decltype(std::forward<Function>(func)(1, 2, 3))
{
    return std::forward<Function>(func)(1, 2, 3);
}

template<typename Function>
auto higherOrderFun(Function&& func)
-> decltype(std::forward<Function>(func)(1, 2))
{
    return std::forward<Function>(func)(1, 2);
}
Run Code Online (Sandbox Code Playgroud)

可能过载优先级为

 struct low_priority {};
 struct high_priority : low_priority{};

template<typename Function>
auto higherOrderFunImpl(Function&& func, low_priority)
-> decltype(std::forward<Function>(func)(1, 2))
{
    return std::forward<Function>(func)(1, 2);
}

template<typename Function>
auto higherOrderFunImpl(Function&& func, high_priority)
-> decltype(std::forward<Function>(func)(1, 2))
{
    return std::forward<Function>(func)(1, 2);
}

template<typename Function>
auto higherOrderFun(Function&& func)
-> decltype(higherOrderFun(std::forward<Function>(func), high_priority{}))
{
    return higherOrderFun(std::forward<Function>(func), high_priority{});
}
Run Code Online (Sandbox Code Playgroud)

如果您想使用florestan 的 arity 特征,可能会导致:

template<typename F>
decltype(auto) higherOrderFun(F&& func)
{
    if constexpr (arity_v<std::decay_t<F>, MaxArity> == 3)
    {
        return std::forward<F>(func)(1, 2, 3);
    }
    else if constexpr (arity_v<std::decay_t<F>, MaxArity> == 2)
    {
        return std::forward<F>(func)(1, 2);
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)