是否有将函数模板作为模板参数传递的解决方法?

Is there any workaround for passing a function template as a template parameter?

我正在尝试制作一个函数模板,该模板将函数模板作为模板参数,然后 returns 使用传入的普通函数参数调用时该函数的结果。它可以像这样使用这个:

auto fooPtr = func<std::make_unique, Foo>(...);

该函数的要点是允许模板类型推导,即使在让另一个函数执行实例构造时也是如此。我已经在我的代码中的很多地方手动执行此操作,如下所示:

auto fooPtr = std::make_unique<decltype(Foo{...})>(...);

我从 到我发布的问题中得到了辅助函数的想法。他建议为特定类型制作一个,但我想要一个可用于任何类型的函数。

这是我到目前为止的想法:

template
<auto F, template<typename U> class T, typename... Args>
std::result_of_t<decltype(F)> 
func(Args&&... args, std::enable_if_t<std::is_invocable_v<decltype(F), Args...>>* = nullptr)
{
    return F<decltype(T{std::forward<Args>(args)...})>(std::forward<Args>(args)...);
}

但我无法让它工作。

我走在正确的轨道上吗?我正在尝试做的事情是否可行?

不幸的是,您不能将模板函数作为模板参数传递,除非您明确指定模板参数,例如:

template<auto T>
auto func(auto&&... args) {
    return T(std::forward<decltype(args)>(args)...);
}

struct Foo { Foo(int i) {} };

int main() {
    auto unique_foo = func<std::make_unique<Foo, int>>(1);
}

然而,您可以毫无问题地传递模板函数对象,因此以下方法可行:

template<class T>
struct unique {
    auto operator()(auto&&... args) {
        return std::make_unique<T>(std::forward<decltype(args)>(args)...);
    }
};

template<class T>
struct shared {
    auto operator()(auto&&... args) {
        return std::make_shared<T>(std::forward<decltype(args)>(args)...);
    }
};

template<template<class> class F, class T, class... Args>
  requires std::is_invocable_v<F<T>, Args...>
auto func(Args&&... args) {
    return F<T>{}(std::forward<Args>(args)...);
}

struct Foo { Foo(int i) {} };

int main(){
    auto foo_unique = func<unique, Foo>(1);
    auto foo_shared = func<shared, Foo>(2);
}

godbolt example

如果您还需要通过传递给 std::make_unique 的参数推断出 class 的模板参数(就像在您的链接示例中一样),您可以为 func 添加重载处理模板化类型:

template<template<class...> class T, class... Args>
using deduced_type = decltype(T{std::declval<Args>()...});

template<template<class> class F, template<class...> class T, class... Args>
  requires std::is_invocable_v<F<deduced_type<T,Args...>>, Args...>
auto func(Args&&... args) {
    return F<deduced_type<T, Args...>>{}(std::forward<Args>(args)...);
}

godbolt example

根据传入的参数将模板参数推导为您的类型T

template<class A, class B>
struct Foo { Foo(A,B) {} };

struct Bar { Bar(int i) {} };


int main(){
    // automatically deduces the types for A, B in Foo based on arguments
    auto foo_unique = func<unique, Foo>(1, 2);

    // the normal overload of func handles non-templated classes:
    auto bar_unique = func<unique, Bar>(1);
}