构造函数超载以接受任何功能



我正在尝试创建一个类模板,其构造函数可以将任何形式的函数作为参数,也就是说,它采用函数指针(可以是成员函数指针(和相应的函数参数。此外,应该有一个static_assert检查功能返回类型(取自函数指针(是否匹配类模板参数类型。因此,代码应该看起来像这样:

template <class ReturnType>
struct Bar
{
    template <class RetType, class ... ParamType>
    Bar<ReturnType>(RetType (* func)(ParamType ...), ParamType && ... args) :
        package_(std::bind(func, std::forward<ParamType>(args) ...)),
        function_([this] { package_(); }),
        future_(package_.get_future())
    {
        static_assert(std::is_same<ReturnType, RetType>::value,
            "Type mismatch between class parameter type and constructor parameter type");
    }
    template <class RetType, class ObjType, class ... ParamType>
    Bar<ReturnType>(RetType (ObjType::* func)(ParamType ...), ObjType * obj, ParamType && ... args) :
        package_(std::bind(func, obj, std::forward<ParamType>(args) ...)),
        function_([this] { package_(); }),
        future_(package_.get_future())
    {
        static_assert(std::is_same<ReturnType, RetType>::value,
            "Type mismatch between class parameter type and constructor parameter type");
    }
    std::packaged_task<ReturnType()> package_;
    std::function<void()> function_;
    std::future<ReturnType> future_;
};

这个想法是为这些情况编译了代码,并允许在没有错误的情况下(通过函数调用操作员(调用Bar::function_

struct Foo
{
    int foo(int i) {
        return i;
    }
    int foo() {
        return 1;
    }
};
int foo(int i)
{
    return i;
}
int foo()
{
    return 1;
}
int main()
{
    Foo f = Foo();
    Bar<int> b1(&Foo::foo, &f, 1);
    Bar<int> b2(&Foo::foo, &f);
    Bar<int> b3(foo, 1);
    Bar<int> b4(foo);
    return 0;
}

不幸的是,我在模板元编程中的经验接近零,即使我在这里遇到了几个问题,并尝试了几种解决我的问题的方法,例如对构造函数使用更广泛的方法

template <class RetType, class ... ParamType>
Bar<ReturnType>(RetType func, ParamType && ... args)

并将其与type_traits结合以确定返回类型(,我还没有找到一种方法来制作这项工作。我可以对允许此功能的构造函数进行什么更改?

编辑:

max66的答案解决了我的原始问题,但是,出现了一个新问题,我在上一个问题中没有考虑过。我也希望能够将变量传递给构造函数,例如:

int main()
{
    Foo f = Foo();
    int i = 1;
    Bar<int> b1(&Foo::foo, &f, i); // Error
    Bar<int> b2(&Foo::foo, &f, 1); // Ok
    Bar<int> b3(&Foo::foo, &f); // Ok
    Bar<int> b4(foo, i); // Error
    Bar<int> b5(foo, 1); // Ok
    Bar<int> b6(foo); // Ok
    return 0;
}

但是,在用Error标记的情况下显示了编译器错误。我猜这是因为构造函数中的参数func使用ParamType确定其类型(在b1b4的情况下与实际ParamType S不匹配(,但是我不知道如何解决此问题...

您可能要使用std::invoke。它处理为您使用成员功能指针和常规功能的工作。

作为您可以做的事情的概述:

#include <functional>
#include <type_traits>
#include <utility>
template<typename F>
class Bar
{
    F f_;
public:
    template<typename TF>
    Bar(TF && f)
        : f_{ std::forward<TF>(f) }
    {}
    template<typename... Args>
    decltype(auto) operator()(Args &&... args) {
        return std::invoke(f_, std::forward<Args>(args)...);
    }
};
template<typename F>
auto make_bar(F && f)
{
    return Bar<std::decay_t<F>>{ std::forward<F>(f) };
}

可以像这样使用:

auto b1 = make_bar(&f);
auto result = b1(myArg1, myArg2); // etc
auto b2 = make_bar(&Foo::fn);
auto result = b1(foo, arg1);

至少,我建议让Bar以函数对象类型为模板参数,以便您不必使用std::function,但是如果您想使用确切的调用语法,则可以是也使用std::invokestd::invoke_result完成。

对不起,但是...如果您希望函数的返回类型等于类的模板参数...为什么不简单地强加它?

我的意思是...您可以使用ReturnType而不是RetType,如下所示

template <typename ReturnType>
struct Bar
{
    template <typename ... ParamType>
    Bar<ReturnType> (ReturnType (*func)(ParamType ...), ParamType && ... args)
      : package_(std::bind(func, std::forward<ParamType>(args) ...)),
        function_([this] { package_(); }),
        future_(package_.get_future())
     { }
    template <typename ObjType, typename ... ParamType>
    Bar<ReturnType> (ReturnType (ObjType::* func)(ParamType ...),
                     ObjType * obj, ParamType && ... args)
      : package_(std::bind(func, obj, std::forward<ParamType>(args) ...)),
        function_([this] { package_(); }),
        future_(package_.get_future())
     { }

- 编辑 -

解决第二个问题,如果您对移动参数不感兴趣,则可以丢弃std::forward&&,然后简单地写

template <typename ReturnType>
struct Bar
{
    template <typename ... ParamType>
    Bar<ReturnType> (ReturnType (*func)(ParamType ...), 
                     ParamType const & ... args)
      : package_(std::bind(func, args...)),
        function_([this] { package_(); }),
        future_(package_.get_future())
     { }
    template <typename ObjType, typename ... ParamType>
    Bar<ReturnType> (ReturnType (ObjType::* func)(ParamType ...),
                     ObjType * obj, ParamType const & ... args)
      : package_(std::bind(func, obj, args...)),
        function_([this] { package_(); }),
        future_(package_.get_future())
     { }

相关内容

最新更新