Передать объект функтора в конструктор шаблонного класса - PullRequest
0 голосов
/ 23 января 2019

Представьте, что у нас есть шаблон класса.Примерно так:

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;

Теперь мы хотим передать объект-конструктор / указатель функции / лямбду в его конструктор, чтобы мы могли его использовать.

Я пробовал что-то подобное, нополучил ошибку времени выполнения

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 и без передачи typename для моего объекта функтора?Я хотел бы использовать это таким образом

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

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Я пытался что-то подобное, но получил ошибку времени выполнения

Как Матье Брухер указал их ответ вы можете 't хранить _func как ссылку, так как объект, с которым вы связываете ссылку, умирает в конце вызова конструктора.Это можно исправить, если сохранить значение _func по значению.

Можно ли как-нибудь это сделать, не используя std :: function и не передавая typename для моего объекта-функтора?Я хотел бы использовать это таким образом

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

Это на самом деле довольно легко сделать.Вам все равно придется использовать std::function в качестве типа хранилища и типа параметра конструктора, но вам не нужно его указывать.Используя псевдоним типа , мы можем указать тип предиката в терминах типа членов класса.Это дает нам

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; 
}
0 голосов
/ 23 января 2019

Нет, это не сработает из-за ссылки на временный объект (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)
...