C++ 将表达式模板存储在 class 中,其对象将成为向量的一部分

C++ Store an expression template inside a class whose objects will be part of a vector

[为了清晰和拼写错误进行了大量编辑,现在尝试解决方案,旧版本在最后]

新版问题

我有一个 class 需要存储一个仿函数。问题在于仿函数是一个表达式模板(意味着每个仿函数都是不同类型的)。最重要的是,我需要将 class 的所有对象收集到一个向量中。

低于我的尝试:

我没有将仿函数的代码写成表达式模板,因为它太长了。因此,我将通过尝试存储两个不同 classes

的两个仿函数来测试代码
struct FunctorTypeA {
    double a;
    FunctorTypeA(const double ap): a(ap) {}
    double operator()(const double x){ return a;}
};

struct FunctorTypeB {
    double a, b;
    FunctorTypeB(const double ap, const double bp): a(ap), b(bp) {}
    double operator()(const double x){ return a+b*x;}
};

我认为,如果我错了请纠正我,如果下面的代码适用于上面的两个仿函数,它应该适用于任何使用表达式模板构造的仿函数。

第一个想法是

template <typename functorType> struct myClass {
    functorType    functor;
    myClass(functorType funct): functor(funct){}
};

我可以将仿函数存储在 class 的对象中,其中:

FunctorTypeA functor1(1.2);
FunctorTypeB functor2(1.5, 5.0);
myClass      myObj1(functor1);
myClass      myObj2(functor2);
cout << myObj1.functor(0.2) << " " << myObj1.functor(0.2) << "\n\n";

但是我无法将这些对象存储在 std::vector 中,因为它们具有不同的类型。

因此我尝试了:

struct myClass2Base {
    virtual ~TrialClassBase() = default;
    virtual double functor(const double x) = 0;
};

template <typename functorType> struct myClass2 : public myClass2Base {
    functorType    functorStored;
    myClass2(functorType funct): functorStored(funct){}
    double functor(const double x){return functorStored(x);}
};

并且我可以构建这些对象的矢量作为

std::vector<myClass2Base*> vecOfObj;
vecOfObj.push_back(new myClass2(functor1));
    
cout << vecOfObj[0]->functor(0.3) << "\n\n";

这个有效。 有更好的解决方案吗?

谢谢!

旧版问题

我有一个 class 需要存储一个仿函数,它是一个表达式模板(意味着每个函数都是不同类型的)。我还需要将 class 的对象放在 std::vector.

我的尝试是

struct TrialClassBase{
    virtual double get_functor(double) = 0;
};

template <typename derived> struct TrialClass : public TrialClassBase {
    derived functor;
    TrialClass(derived fun): functor(fun){}
    double get_functor(double x) {return functor(x);}
};

std::vector<shared_ptr<TrialClassBase>> vecOfObjs;

然后我尝试向矢量添加一个对象。作为示例,我使用 std::function,仅作为示例:在我的例子中,仿函数将是一个表达式模板。

std::function<double(double)>  funcccc = [](double x){return x*x;};
vecc.emplace_back(TrialClass(funcccc));
cout << vecc[0]->get_functor(0.3) <<"\n\n";

编译失败。我犯了什么错误?我怎样才能做我想做的事?

谢谢!

您构建的 shared_ptr 无效

正如评论中指出的那样:

  • 一个基class应该总是有一个虚拟析构函数
  • push_back优先
struct TrialClassBase {
  virtual double get_functor(double) = 0;
  virtual ~TrialClassBase() = default;
};

template <typename derived> struct TrialClass : public TrialClassBase {
  derived functor;
  TrialClass(derived fun) : functor(fun) {
  }
  double get_functor(double x) {
    return functor(x);
  }
};

std::vector<std::shared_ptr<TrialClassBase>> vecc;

int main() {
  std::function<double(double)> funcccc = [](double x) { return x * x; };
  vecc.push_back(
    std::make_shared<TrialClass<std::function<double(double)>>>(funcccc));
  std::cout << vecc[0]->get_functor(0.3) << "\n\n";
}

我看到你改进了你的问题。 是的,有更好的解决方案。

std 库为您提供的一个很好的解决方案是使用类型擦除 std:function

#include <vector>
#include <functional>
#include <iostream>
#include <cmath>

struct FunctorTypeA {
    double a;
    FunctorTypeA(const double ap): a(ap) {}
    auto operator()([[maybe_unused]]const double x) const { return a;}
};


int main(){
    auto funcVec{std::vector<std::function<double(double)>>{}};
    funcVec.push_back(FunctorTypeA{3.14}); // functor allowed
    funcVec.push_back([](double x){return x;}); // lambda allowed
    funcVec.push_back(sqrt); // function pointer allowed, e.g. C math function

    for(auto&& f:funcVec){
        std::cout << f(2.0) << '\n';
    }
}

这样您就不会将继承和指针转换复杂化。那里容易出错。 std::vectorstd::function 将完成所有清理工作。 (这是您在指针向量解决方案中很容易错过的东西)

注意:std::function可能会执行动态分配。但是 std::vector 也是如此,并且继承有 vtable 开销。