Tomáš Zato Tomáš Zato - 4 months ago 13
C++ Question

Can I define implicit conversion from std::function to std::shared_ptr<MyClass>?

I have a class that works as a predicate to select value from list.

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


Originally, I used lambda functions but this created lot of repetitive garbage code. So instead, I want to use predicate classes that use inheritance. For example:

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


To allow inheritance do it's deed, pointers are given rather than values:

class SomeDataObject {
// Removes all values that satisfy the given predicate
int removeValues(const std::shared_ptr<Predicate> pred);
}


Now we are surely stil going to use lambdas in cases where code would not be repetitive (eg. some special case). For this purpose,
PredicateLambda
has been created:

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


The nasty effect of this is that whenever lambda is used, it must be wrapped into
PredicateLambda
constructor:

myObject.deleteItems(std::make_shared<PredicateLambda>([]->bool{ ... lambda code ... }));


This is ugly. I have two options:


  • for every function that accepts predicate, have an overload that does the conversion seen above. This duplicates number of methods in header file

  • Have an implicit conversion from
    std::function<bool(const QString& val)>
    to
    std::shared_ptr<Predicate>
    which would execute this:

    std::shared_ptr<Predicate> magicImplicitConversion(const StdPredicateLambda& lambdaFn) {
    return std::make_shared<PredicateLambda>(lambdaFn);
    }



I came here to ask whether the second option is possible. If it is, does it carry any risk?

Answer

If you don't want to use template to not expose code, you may use std::function:

class SomeDataObject {
    // Removes all values that satisfy the given predicate
    int removeValues(std::function<bool(const QString&)> pred);
};

and your predicate

class PredicateMaxLength {
public:
    explicit PredicateMaxLength(int max) : maxLength(max) {}
    bool operator ()(const QString& val) const {return val.length()<maxLength;}
protected:
    int maxLength;
};

So you can use either

SomeDataObject someDataObject;

someDataObject.removeValues(PredicateMaxLength(42));
someDataObject.removeValues([](const QString& s) { return s.size() < 42; });
Comments