【问题标题】:Using a CRTP based class as an argument of a function, without knowing the template parameter在不知道模板参数的情况下使用基于 CRTP 的类作为函数的参数
【发布时间】:2020-03-12 16:24:21
【问题描述】:

我目前正在尝试编写一个微分方程求解器,并希望将类用作运算符,它定义了一个重载的 operator() 以便我可以将运算符用作函子。目标是我有一些数据,为了表示温度的参数,让我们取 T,我想提供一个像 ddt(T) == laplacian(T) 这样的接口,其中 ddt 是关于的一阶偏导数时间,拉普拉斯算子是关于空间的二阶偏导数。在这个例子中,我只是求解一个热方程。

由于我想允许不同的时间和空间方案,我想有两个时间和空间基类,然后从这些基类派生出近似时间或空间的数值方案,其中我的 operator() 是定义为纯虚函数。

我希望能够从它的operator()返回一个空间运算符的引用,所以我使用CRTP在基类中指定返回类型。

时间运算符位于等式的左侧,应该处理右侧的所有信息。因此,在时间类中定义的 operator== 从右侧接收一个运算符。 问题出在这里: operator== 的参数要求我指定要传入的右侧运算符的类型,但是我不知道应该使用哪种类型模板参数,因为我想稍后接受不同类型的运算符。鉴于下面的代码,有没有一种干净的方法来解决这个问题?

#include <iostream>
#include <vector>

using Vector = std::vector<double>;

template<class Type>
struct spaceOperatorBase {
    virtual Type operator()(Vector &data) = 0;
    protected:
    Vector _data;
};

struct laplacianOperator : public spaceOperatorBase<laplacianOperator> {
    laplacianOperator operator()(Vector &data) final override {
        std::cout << "solving laplacian operator" << std::endl;
        this->_data = data;
        return *this;
    }
};

template <class Type>
struct timeOperatorBase {
    virtual Type operator()(Vector &phi) = 0;
    virtual void operator==(const spaceOperatorBase<laplacianOperator> &rhs) = 0; // <- how to get rid here of the dependency on <laplacianOperator>?
};

struct eulerOperator : timeOperatorBase<eulerOperator> {

    eulerOperator operator()(Vector &phi) {
        std::cout << "preparing time-integration" << std::endl;
        return *this;
    };

    void operator==(const spaceOperatorBase<laplacianOperator> &rhs) { // <- how to get rid here of the dependency on <laplacianOperator>?
        std::cout << "solving equation" << std::endl;
    };
};

int main() {

Vector T;
laplacianOperator laplacian;
eulerOperator ddt;

ddt(T) == laplacian(T);

return 0;
}

【问题讨论】:

  • 从数学上讲,ddt(T)laplacian(T) 纯粹是 T 的 函数。所以我想挑战您的第一个陈述,即您“想将类用作运算符” .您将这些操作实现为对象的实例而不仅仅是函数的理由是什么?为什么你的spaceOperatorBase 需要拥有一个向量而不是作为另一个参数?您可以将函数签名定义为一种类型,因此ddt(T)laplacian(T) 的所有各种实现仍然可以“继承”一个通用函数签名。
  • 好吧,这是一个适用于本网站的玩具示例,显然看看这个简单的示例您可能有一点意思。但是,对于我的实际问题,我确实有理由想要使用函子,该函子直接对他们不拥有的数据进行操作(所以我最终不会得到同一个操作符的多个实例,其中只有它操作的数据发生变化)我有充分的理由想要将对象传递给时间运算符,这需要来自空间运算符的一些信息,因此只传递整个对象会更简单。但同样,在不知道类型的情况下,我不知道如何

标签: c++ templates polymorphism crtp


【解决方案1】:

我终于找到了适合我的方法。当我使用 c++17 时,我可以使用 std::variant 和 std::visit 作为虚方法的参数类型。这是满足我需要的完整代码。在这里发布给任何在谷歌上搜索类似问题的人。

#include <iostream>
#include <vector>
#include <variant>

using Vector = std::vector<double>;

template<class Type>
struct spaceOperatorBase {
    virtual Type operator()(Vector &data) = 0;
    virtual void printMyType() const = 0;
    protected:
    Vector _data;
};

struct laplacianOperator : public spaceOperatorBase<laplacianOperator> {
    laplacianOperator operator()(Vector &data) final override {
        std::cout << "solving laplacian operator" << std::endl;
        this->_data = data;
        return *this;
    }
    void printMyType() const final override {
        std::cout << "I am a laplacian operator" << std::endl;
    }
};

// variant that holds all possible operators, can include multiple ...
using MyOperators = std::variant<laplacianOperator>;

template <class Type>
struct timeOperatorBase {
    virtual Type operator()(Vector &phi) = 0;
    virtual void operator==(const MyOperators &rhs) = 0; // <- how to get rid here of the dependency on <laplacianOperator>?
};

struct eulerOperator : timeOperatorBase<eulerOperator> {

    eulerOperator operator()(Vector &phi) {
        std::cout << "preparing time-integration" << std::endl;
        return *this;
    };

    void operator==(const MyOperators &rhs) { // <- how to get rid here of the dependency on <laplacianOperator>?
        std::cout << "solving equation" << std::endl;
        // accessing specific information from rhs
        auto operatorAccessor = [](const auto &accessor){
            accessor.printMyType();
        };
        std::visit(operatorAccessor, rhs);
    };
};

int main() {

Vector T;
laplacianOperator laplacian;
eulerOperator ddt;

ddt(T) == laplacian(T);

return 0;
}

这会将以下内容打印到控制台

preparing time-integration
solving laplacian operator
solving equation
I am a laplacian operator

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多