У меня есть класс, который работает как предикат для выбора значения из списка.Могу ли я определить неявное преобразование из std :: function в std :: shared_ptr <MyClass>?
class Predicate {
public:
// In this example, I am using QString as value type
// this is not what happens in actual code, where more complex data is being validated
virtual bool evaluate(const QString& val) const = 0;
};
Первоначально, я использовал функции лямбда, но это создало много повторяющегося кода мусора. Поэтому вместо этого я хочу использовать предикатные классы, которые используют наследование. Например:
class PredicateMaxLength: public RowPredicate {
public:
PredicateMaxLength(const int max) : maxLength(max) {}
virtual bool evaluate(const QString& val) const {return val.length()<maxLength;}
protected:
const int maxLength;
};
Чтобы разрешить наследование сделать это дело, указатели дают, а не значение:
class SomeDataObject {
// Removes all values that satisfy the given predicate
int removeValues(const std::shared_ptr<Predicate> pred);
}
Теперь мы, безусловно, стили собираемся использовать лямбды в тех случаях, когда код не будет повторяться (например, какой-нибудь особый случай). Для этого PredicateLambda
было создано:
typedef std::function<bool(const QString& val)> StdPredicateLambda;
class PredicateLambda: public Predicate {
public:
PredicateLambda(const StdPredicateLambda& lambda) : RowPredicate(), callback_(lambda) {}
virtual bool evaluate(const QString& val) const override {return callback_(val);}
protected:
const StdPredicateLambda callback_;
};
Противный эффектом этого является то, что всякий раз, когда используется лямбда, он должен быть обернут в PredicateLambda
конструктор:
myObject.deleteItems(std::make_shared<PredicateLambda>([]->bool{ ... lambda code ... }));
Это некрасиво. У меня есть два варианта:
- для каждой функции, которая принимает предикат, имеет перегрузку, которая выполняет преобразование, указанное выше. Это дублирует ряд методов в заголовочном файле
Есть неявное преобразование из
std::function<bool(const QString& val)>
вstd::shared_ptr<Predicate>
, исполняющих бы это:std::shared_ptr<Predicate> magicImplicitConversion(const StdPredicateLambda& lambdaFn) { return std::make_shared<PredicateLambda>(lambdaFn); }
Я пришел сюда, чтобы спросить, возможно ли второй вариант. Если да, несет ли он какой-либо риск?
Зачем использовать 'shared_ptr' вместо' const & '? Во всех случаях, если вы можете, вы должны сделать 'removeValues' шаблонным методом. – Holt
@ Холл Мне нужно, чтобы наследование работало правильно. Когда они передаются по значению, объекты, похоже, теряют перегруженные функции, которые называются [срезы объектов] (http://stackoverflow.com/a/274634/607407). –
Да, но 'const &' не * pass by value *, это * pass by reference *, и он хорошо работает с виртуальной функцией. Но на самом деле, у вас будет такая же проблема, см. Мой ответ для реального решения на C++. – Holt