Общая функция, которая принимает постоянные и неконстантные данные и связанную функцию - PullRequest
0 голосов
/ 18 декабря 2018

Чтобы лучше понять название вопроса, рассмотрите следующий код:

template <typename T>
void write(const T& /*data*/)
{
    // use data as const
}

template <typename T>
void read(T& /*data*/)
{
    // modify data
}

struct S { 
    int a;
    int b;
    // a lot of primitive types here
};

void output(const S& s)
{
    write(s.a);
    write(s.b);
    // ...
}

void input(S& s)
{
    read(s.a);
    read(s.b);
    // ...
}

int main()
{
    S s;
    input(s);
    output(s);
}

У меня есть write и read функции, которые управляют примитивными данными, такие как int, double и т. Д. Iу меня есть несколько структурных типов, таких как S, которые содержат много примитивных членов данных, и мне нужно вводить и выводить такие типы с помощью соответствующих функций input и output (существует много перегрузок для различных типов).Как вы можете видеть, содержание функций output и input в основном одинаково, отличаются только внутренние функции и константность типов.Я хотел бы сделать некоторую универсальную (шаблонную) функцию use, чтобы исключить дубликаты кода из input / output функций.

Я думаю, что подпись шаблона будет следующей (но я могу что-то пропустить):

template <typename F, typename T>
void use(T& t) { ... }

Так что я мог бы вызвать функцию use из input / output следующим образом:

use<write, S>(s); // in output function
use<read, S>(s);  // in input fuction

Как архивировать это (или подобное) поведение, чтобы устранитьдубликаты кода?Я использую C ++ 14.

Ответы [ 3 ]

0 голосов
/ 18 декабря 2018

Вы можете определить интерфейс используемого шаблона:

template<class M, class S>
void use(S &&s) {
    M::method(s.a);
    M::method(s.b);
};

Затем реализовать его:

template <typename T>
void write(const T& /*data*/)
{
    // use data as const
}

struct writer {
    template <typename T>
    static void method(const T& t)
    {
        write(t);
    }
};

Теперь вы можете использовать его:

use<writer>(s);

Для read это то же самое:

struct reader {
    template <typename T>
    static void method(T& t)
    {
        read(t);
    }
};

use<reader>(s);
0 голосов
/ 18 декабря 2018

Мне кажется, я поняла, что вы хотите, но это невозможно.В настоящее время нет способа реализовать в C ++ универсальную потоковую передачу для всех классов.Требуется доступ к информации, такой как количество полей, которые имеет класс, их относительный адрес, а также тип во время компиляции.

В настоящее время они работают над добавлением этого в C ++ в течение многих лет, ищите Reflection TS.Насколько я знаю, он не будет готов к C ++ 20.

Однако вы можете организовать свой код так, чтобы каждый метод чтения / записи был легко реализован.Например:

class A : public B, public C
{
   private:
   vector<int> m_v;
   int m_x;
};

Затем реализовать запись для него как

template<>
void write(const A& a)
{
     write((const B&)a);
     write((const C&)a);
     write(a.m_v);
     write(a.m_x);
}

В то время как для общих структур данных, таких как std::vector<T>, реализовать запись через write<T>.Это требует времени, но сделать его техническим, а использование перенаправлений может сэкономить много кода и времени.

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

0 голосов
/ 18 декабря 2018
template <typename S, typename F>
void use(S&& s, F&& f)
{
    f(s.a);
    f(s.b);
    f(s.c);
}

Использование:

use(s, [](const auto& x){ write(x); });
use(s, [](auto& x)      { read(x); });

живой пример на wandbox.org


Если вам нужно несколько типов:

template <typename S, typename Target>
using EnableFor = std::enable_if_t<std::is_same_v<std::decay_t<S>, Target>>;

template <typename S, typename F>
auto use(S&& s, F&& f) -> EnableFor<S, S0>
{
    f(s.a);
    f(s.b);
    f(s.c);
}

template <typename S, typename F>
auto use(S&& s, F&& f) -> EnableFor<S, S1>
{
    f(s.d);
    f(s.e);
    f(s.f);
}

Использование:

int main()
{
    S0 s0; 
    use(s0, [](const auto& x){ write(x); });
    use(s0, [](auto& x)      { read(x); });

    S1 s1;
    use(s1, [](const auto& x){ write(x); });
    use(s1, [](auto& x)      { read(x); });
}

живой пример на wandbox.org

...