将仿函数对象传递给模板化 class 的构造函数

Pass an functor object to constructor of templated class

假设我们有一个模板 class。像这样

template<typename T>
class MyTemplateClass {
private: 
    T _v1, _v2;
public: 
    MyTemplateClass(T v1, T v2)
    {
        _v1 = v1;
        _v2 = v2;
    }
    bool Act()
    {
        return _v1 > _v2;
    }
}; 

//usage
MyTemplateClass<int> test(1, 2);
std::cout << test.Act() << std::endl;

现在我们要传递一个仿函数对象/函数指针/lambda给他的构造函数,这样我们就可以使用了。

我试过类似的方法,但出现运行时错误

template<typename T, typename F>
class MyTemplateClass {
private: 
    T _v1, _v2;
    const F& _func;
public: 
    MyTemplateClass(T v1, T v2, F functor)
        :_func(functor)
    {
        _v1 = v1;
        _v2 = v2;
    }
    bool Act()
    {
        return _func(_v1, _v2);
    }
}; 

bool isGreater(int a, int b)
{
    return a > b;
} 


//later
    MyTemplateClass<int, std::function<bool(int, int)>> test(1, 2, isGreater);
    std::cout << test.Act() << std::endl; 

那么我怎样才能实现这个功能呢?有什么方法可以在不使用 std::function 并且不为我的仿函数对象传递类型名的情况下使它工作吗? 我想这样用

MyTemplateClass<int> test(1, 2, isGreater);

不,由于对临时对象 (functor) 的引用,这不会起作用:

const F& _func;
public: 
    MyTemplateClass(T v1, T v2, F functor)
    :_func(functor)

存储对象:

F _func;
public: 
    MyTemplateClass(T v1, T v2, F functor)
    :_func(std::move(functor))

或者在某些您知道对象生命周期的情况下,将其作为 const& 传递:

MyTemplateClass(T v1, T v2, const F& functor)

I've tried something like this, but got runtime-error

As Matthieu Brucher pointed out 您不能将 _func 存储为引用,因为您将引用绑定到的对象在构造函数调用结束时死亡。更改为按值存储 _func 将解决此问题。

Is there any way to make this working without using std::function and without passing typename for my functor object? I would like to use it this way

MyTemplateClass<int> test(1, 2, isGreater);

这其实很容易做到。您仍然必须使用 std::function 作为存储类型和构造函数参数类型,但不必指定它。利用 type alias 我们可以根据 class 成员的类型指定谓词类型。这给了我们

using predicate = std::function<bool(T, T)>;

将其添加到 class 后,我们可以将其修改为

template<typename T>
class MyTemplateClass {
public:
    using predicate = std::function<bool(T, T)>;
    MyTemplateClass(T v1, T v2, predicate functor)
        :_func(std::move(functor))
    {
        _v1 = v1;
        _v2 = v2;
    }
    bool Act()
    {
        return _func(_v1, _v2);
    }
private: 
    T _v1, _v2;
    predicate _func;
}; 

现在可以像

一样使用
int main()
{
    MyTemplateClass<int> test(1, 2, isGreater);
    std::cout << test.Act() << std::endl; 
}