简体   繁体   中英

Pass an functor object to constructor of templated class

Imagine we have a template class. Something like this

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;

now we want to pass a functor object / function pointer / lambda to his constructor so that we can use it.

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

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; 

so how could I achieve this functionality? 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);

Nope, this is not going to work because of the reference on a temporary object ( functor ):

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

Store the object:

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

Or in some cases where you know the lifetime of the object, pass it as const&:

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

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

As Matthieu Brucher pointed out their answer you can't store _func as a reference since the object you bind the reference to dies at the end of the constructor call. Changing to storing _func by value will fix that.

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

This is actually pretty easy to do. You'll still have to use a std::function as the storage type and constructor parameter type but won't have to specify it. Utilizing a type alias we can specify the predicate type in terms of the type of the class members. That gives us

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

and after adding it to the class we can rework it to be

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

Which can be used now like

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM