简体   繁体   English

使用基于 CRTP 的类作为函数的参数,而不知道模板参数

[英]Using a CRTP based class as an argument of a function, without knowing the template parameter

I am currently trying to write a differential equation solver and want to use classes as operators, which define an overloaded operator() so that I can use the operators as functors.我目前正在尝试编写一个微分方程求解器,并希望使用类作为运算符,它定义了一个重载的 operator() 以便我可以将运算符用作函子。 The goal is that I have some data, lets take T for the sake of argument representing temperature, and I want to provide an interface like ddt(T) == laplacian(T), where ddt is the first order partial derivative with respect to time, and laplacian is the second order partial derivative with respect to space.目标是我有一些数据,为了代表温度的参数,让我们取 T,我想提供一个接口,如 ddt(T) == laplacian(T),其中 ddt 是关于时间,拉普拉斯算子是关于空间的二阶偏导数。 In this example, I am simply solving a heat equation.在这个例子中,我只是在求解一个热方程。

Since I want to allow for different time and space schemes, I want to have two base classes for time and space, and then derive my numerical schemes which approximate either time or space from those base classes, where my operator() is defined as a pure virtual function.因为我想允许不同的时间和空间方案,所以我想有两个时间和空间的基类,然后从这些基类派生出近似时间或空间的数值方案,其中我的 operator() 被定义为纯虚函数。

I want to be able to return a reference of the space operator from its operator(), so I use CRTP to specify the return type in the base class.我希望能够从其 operator() 返回空间运算符的引用,因此我使用 CRTP 在基类中指定返回类型。

The time operator is on the left-hand side of the equation and is supposed to process all the information from the right-hand side.时间运算符位于等式的左侧,应该处理来自右侧的所有信息。 Therefore, the operator==, defined in the time class, receives an operator from the right-hand side.因此,在时间类中定义的 operator== 从右侧接收一个运算符。 Here lies the problem: The argument of the operator== requires me to specify the type of the right-hand side operator I am passing in, however, I don't know which type I should use for the template argument as I want to accept different types of operators later.问题就在这里: operator== 的参数要求我指定我传入的右侧运算符的类型,但是,我不知道我应该为模板参数使用哪种类型,因为我想稍后接受不同类型的运算符。 Given the code below, is there a clean way to get around this issue?鉴于下面的代码,有没有一种干净的方法来解决这个问题?

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

I finally figured out a way that works for me.我终于想出了一个对我有用的方法。 As I am using c++17, I can use std::variant and std::visit for the argument type of the virtual method.当我使用 c++17 时,我可以使用 std::variant 和 std::visit 作为虚方法的参数类型。 Here is the full code which is working for my needs.这是满足我需要的完整代码。 Posting it here for anyone googling a similar problem.把它贴在这里供任何在谷歌上搜索类似问题的人使用。

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

This will print the following to the console这会将以下内容打印到控制台

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM