我可以定义从std :: function到std :: shared_ptr <myclass>的隐式转换吗?

时间:2016-08-02 12:22:58

标签: c++ c++11 std implicit-conversion

我有一个类作为谓词来从列表中选择值。

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

最初,我使用了lambda函数,但这创建了大量重复的垃圾代码。所以相反,我想使用使用继承的谓词类。例如:

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

现在我们肯定会在代码不重复的情况下使用lambdas(例如某些特殊情况)。为此,已创建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_;
};

令人讨厌的效果是每当使用lambda时,它必须被包装到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);
    }
    

我来这里询问第二种选择是否可行。如果是,它是否有风险?

2 个答案:

答案 0 :(得分:3)

如果您不想使用template不公开代码,可以使用std::function

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

和你的谓词

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

所以你可以使用

SomeDataObject someDataObject;

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

答案 1 :(得分:1)

您需要多态,并且您不想使用模板样式的标头lambdas。并且您希望能够有一些默认情况。

正确的答案是抛弃你的Predicate课程。

使用using Predicate = std::function<bool(const QString&)>;

接下来,请注意您的Predicate子类型基本上是Predicate的工厂(构造函数是工厂),并且具有一些额外的状态。

对于std::function,这样的工厂只是一个返回Predicate的函数。

using Predicate = std::function<bool(const QString&)>;

Predicate PredicateMaxLength(int max) {
  return [max](QString const& str){ return val.length()<max; }
}

PredicateMaxLength的主体进入cpp文件。

如果您的Predicate派生类有一个非常复杂的状态集,只需给它operator()并将其存储在std::function中。 (在非常罕见的情况下,您有一些状态,您应该存储在共享的ptr中,只需将其存储在共享的ptr中)。

std::function<Signature>是一种多态的常规类型。它使用一种称为类型擦除的技术既是一种价值又是多态的,但实际上你可以称它为魔术。

当您传递一个对象时,它是正确的类型,该对象的唯一作业是使用一组参数调用并返回一些值。

要直接回答您的问题,不,您无法在std::functionstd::shared_ptr<yourtype>之间定义转换运算符,而不会使您的程序生成错误,无需诊断。

即使你可以,std::function不是lambda,而lambda也不是std::function。所以你的转换运算符不起作用。