【问题标题】:Pass an functor object to constructor of templated class将仿函数对象传递给模板类的构造函数
【发布时间】:2019-01-23 11:08:34
【问题描述】:

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

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);

【问题讨论】:

  • 取决于您的编译器及其版本,it might be possible to do what you want。如果你可以启用 C++17 模式,那就试试吧。
  • @Someprogrammerdude 它会复制对象并存储对象,尽管 const&?如果是,我将删除我的答案。
  • @MatthieuBrucher 不会的。
  • @Someprogrammerdude 不,我没有。我只能使用 c++11。最好不要使用 std::function

标签: c++ templates lambda stl functor


【解决方案1】:

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

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

有什么方法可以在不使用 std::function 且不为我的仿函数对象传递类型名的情况下使其工作?我想这样使用它

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

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

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

在将它添加到类后,我们可以将其修改为

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; 
}
    

【讨论】:

    【解决方案2】:

    不,由于临时对象 (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)
    

    【讨论】:

    • 具体来说,你的const F&amp; _func;指的是构造函数的functor参数,构造完成后就不再存在了。
    • @L.F.这就是我的想法,在我的回答中添加了一个澄清。
    • @MatthieuBrucher 谢谢,我的愚蠢错误。存储对象正在工作。但是在模板参数中不使用 std::function 怎么样?
    • 你可以使用bool(*)(int, int)作为模板参数,存储一个指向函数的指针。
    • @MatthieuBrucher 但这不适用于函子,对吧?
    猜你喜欢
    • 1970-01-01
    • 2014-06-04
    • 1970-01-01
    • 2017-03-07
    • 1970-01-01
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多