Удобный макрос в случае большого списка аргументов шаблона - PullRequest
0 голосов
/ 30 апреля 2018

В моем проекте у меня есть класс (пусть это будет Shell), который настроен на большое количество параметров. Большинство из этих параметров - это другие классы, которые я определяю в своем проекте, так как для своего проекта я выбрал подход на основе политик.

Объявление класса выглядит примерно так:

template <class int_t, class float_t, class Pol1, class Pol2,..., class PolN>
class Shell : Pol1, Pol2,...,PolN

Два первых аргумента - это целочисленные и плавающие типы, которые должны использоваться. Остальные параметры являются конкретными политиками, определенными в рамках проекта.

Этот тип дизайна удобен для меня, поскольку позволяет избежать большого количества проверок во время выполнения (и мы ориентируемся на производительность во время выполнения). Однако очень сложно (с точки зрения пользователя) вводить список из 10+ аргументов всякий раз, когда он хочет создать экземпляр класса Shell.

По этой причине я решил перенести эту нагрузку на печать в отдельный файл вместе с макросами. Во-первых, я устанавливаю по умолчанию все политики в макрос:

template <class int_t, class float_t, class Pol1 = DEF_1, class Pol2 = DEF_2,..., class PolN = DEF_N>
class Shell : Pol1, Pol2,...,PolN

И параметры шаблона могут быть предоставлены в отдельных файлах, как макросы, а не в объявлении решателя. Например:

#include <shell.cpp>

#define DEF_1 example1
#define DEF_2 example2
...
#define DEF_N exampleN

int main(){
    Shell<int,double> MyShell();
    return 0;
    }

Таким образом, создание экземпляра класса требует только передачи параметров шаблона (остальные +10 параметров передаются через макросы). Определения могут быть даже перемещены в отдельный файл, например:

#include <shell.cpp>
#include "define.hpp"

Это просто обходной путь, так что вам не нужно предоставлять список аргументов более 10 параметров каждый раз, когда вы создаете экземпляр класса. Макросы - лучшее решение, которое я нашел до сих пор. Однако я знаю, что макросы не являются «рекомендуемым» решением в большинстве приложений C ++.

По этой причине я хотел бы знать, является ли это типичной проблемой, и как вы можете ее преодолеть без макросов. Я также хотел бы знать, являются ли макросы «нормальным» решением, или я должен избегать этого дизайна любой ценой. Я был бы признателен за любую помощь / комментарий по этой теме, так как я довольно новичок в C ++

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

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

struct DefaultPol1 {};
struct DefaultPol2 {};
struct DefaultPol3 {};

struct OtherPol1 {};
struct OtherPol2 {};
struct OtherPol3 {};

template<class Pol1 = DefaultPol1, class Pol2 = DefaultPol2, class Pol3 = DefaultPol3>
struct Config
{
    using P1 = Pol1;
    using P2 = Pol2;
    using P3 = Pol3;


    template <class NewPol1>
    using ChangePol1To = Config<NewPol1, Pol2, Pol3>;

    template <class NewPol2>
    using ChangePol2To = Config<Pol1, NewPol2, Pol3>;

    template <class NewPol3>
    using ChangePol3To = Config<Pol1, Pol2, NewPol3>;
};

using DefaultConfig = Config<>;


template <class int_t, class float_t, class C = DefaultConfig>
class Shell : C::P1, C::P2, C::P3
{};


void foo()
{
    using config = DefaultConfig::ChangePol3To<OtherPol3>::ChangePol1To<OtherPol1>;
    Shell<unsigned, double, config> myShell;
}

https://godbolt.org/g/uPrRhc (улучшенная версия, благодаря @ Jarod42!)
(Если вы измените пустые определения структуры на только (прямые) объявления, ошибки компилятора показывают, что выбраны правильные политики).

Присвоение имен возможно улучшилось бы в более широком контексте.

0 голосов
/ 30 апреля 2018

с использованием псевдонима кажется лучше:

template <class int_t, class float_t>
using MyShell = Shell<int_t, float_t, MyPol1, MyPol2, ..., MyPolN>;
...