Использование класса на основе CRTP в качестве аргумента функции без знания параметра шаблона - PullRequest
0 голосов
/ 12 марта 2020

В настоящее время я пытаюсь написать решатель дифференциальных уравнений и хочу использовать классы в качестве операторов, которые определяют перегруженный оператор (), чтобы я мог использовать операторы в качестве функторов. Цель состоит в том, чтобы у меня были некоторые данные, давайте возьмем T для аргумента, представляющего температуру, и я хочу предоставить интерфейс, такой как ddt (T) == laplacian (T), где ddt - частная производная первого порядка по отношению к время, а лапласиан - частная производная второго порядка по пространству. В этом примере я просто решаю уравнение теплопроводности.

Поскольку я хочу учесть различные схемы времени и пространства, я хочу иметь два базовых класса для времени и пространства, а затем вывести свои числовые схемы, которые приближаются либо время, либо пространство из тех базовых классов, где мой оператор () определен как чисто виртуальная функция.

Я хочу иметь возможность вернуть ссылку на оператор пространства из его оператора (), поэтому я использую CRTP для указания типа возвращаемого значения в базовом классе.

Оператор времени находится в левой части уравнения и должен обрабатывать всю информацию из правой части. Следовательно, оператор ==, определенный во временном классе, получает оператор с правой стороны. Здесь кроется проблема: Аргумент оператора == требует от меня указать тип правостороннего оператора, который я передаю, однако я не знаю, какой тип использовать для Шаблонный аргумент, поскольку я хочу принять различные типы операторов позже. Учитывая приведенный ниже код, есть ли чистый способ обойти эту проблему?

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

1 Ответ

0 голосов
/ 14 марта 2020

Я наконец-то нашел способ, который работает для меня. Поскольку я использую c ++ 17, я могу использовать std :: option и 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...