Попытка потребовать указать несколько типов c variadi c типов - PullRequest
0 голосов
/ 02 марта 2020

Это в настоящее время псевдокод, так как это идея, над которой я работаю, прежде чем я начну писать ее как полный код.

Я знаю, что могу создать обычную функцию variadi c, которая использует va_arg и va_list, такие как printf(), однако я хочу избегать их полного использования.

Я думал об использовании вместо этого шаблонных переменных c. Я думал о создании инстанцируемого класса с использованием параметров variadi c. Условие здесь состоит в том, что конструктор этого класса может принимать только два типа, но число каждого типа может варьироваться. Я знаю, что параметры c записаны в коде по сравнению с тем, как компилятор будет интерпретировать и в каком порядке они вызываются, но это не проблема. Порядок, который я выбрал для параметров, условно для удобства чтения и согласованности.

Вот пример псевдокода:

class TypeIn {...}
class TypeOut{...}

template<typename... T1, typename... T2>
class MyObject {
    std::array<TypeIn*> inputs_;
    std::array<TypeOut*> outputs_;
public:
    MyObject(T1&&... inputs, T2&& ... outputs) { ... }
};

Поскольку я все еще работаю в C ++ 17, и пока нет C ++ 20 с концепциями, модулями и сопрограммами, что было бы самым чистым и надежным и эффективным способом убедиться, что T1 является TypeIn, а T2 является TypeOut Класс объекта и для заполнения массивов соответственно? Я мог бы использовать вектор, но как только объект будет сконструирован, размеры входов и выходов не изменятся.

Возможный вариант использования:

using In = TypeIn;
using Out = TypeOut;
MyObject obj( In a, In b, In c, Out x, Out y);

И я бы предпочел не чтобы иметь это для синтаксиса, если это вообще возможно:

MyObject<In,In,In,Out,Out> obj( In a, In b, In c, Out X, Out y);

Так как первый более чистый или более читаемый.



Редактировать

Подумав, я подумал, а может ли это работать вместо этого ...

class In {...}
class Out{...}


// template<typename T1 = In, typename T2 = Out>
// T1 must == type In and T2 must == type Out
class MyObject {
private:
     std::vector<In*> inputs_;
     std::vector<Out*> outputs_;

public:
      MyObject() = deafault;

      template<typename... Inputs> // would probably use move semantics or forwarding
      void assignInputs(Inputs&& ... inputs);

      template<typename... Outputs> // would probably use move semantics or forwarding
      void assignOutputs(Inputs&& ... outputs);
};

Однако это заставит пользователя создать объект, а затем вызвать обе функции ... Я был пытаясь сделать все это при строительстве ...

Ответы [ 3 ]

5 голосов
/ 02 марта 2020

В соответствии с вашими комментариями, я думаю, вы ищете что-то вроде

template<typename T1, typename T2>
class MyObject {
    std::vector<T1> inputs_;
    std::vector<T2> outputs_;
public:
    MyObject(std::initializer_list<T1> inputs, std::initializer_list<T2> outputs)
      : inputs_(inputs), outputs_(outputs) { }
};

Для использования в качестве

MyObject obj({a, b, c}, {x, y});

Обратите внимание, что для этого требуется, чтобы оба типа были копируемыми , Он не работает с типами «только для перемещения».


Если вы действительно настаиваете на индивидуальном использовании элементов в качестве аргументов конструктора, это технически возможно, но будет гораздо сложнее реализовать без особых преимуществ.

3 голосов
/ 02 марта 2020

Я пытался сделать все это при создании ...

ИМХО, решение, основанное на списке инициализаторов (см. Ответ грецкого ореха), предпочтительнее, также, чтобы сделать его более понятным, из точка зрения вызывающей стороны, какие аргументы являются входными значениями, а какие являются выходными значениями.

Но ... просто для удовольствия ... если вы действительно хотите сделать все по построению и избегать группировки аргументов (или также смешивая их) ... используя std::tuple, std::tuple_cat(), делегируя конструкторы, std::apply() и if constexpr

#include <iostream>
#include <type_traits>
#include <tuple>
#include <vector>

struct TypeIn  {};
struct TypeOut {};

struct MyObject
 {
   template <typename TargetType, typename T>
   static auto filterVal (T && t)
    {
      if constexpr ( true == std::is_same_v<TargetType, std::decay_t<T>> )
         return std::tuple<TargetType>{std::forward<T>(t)};
      else
         return std::tuple<>{};
    }

   std::vector<TypeIn> is;
   std::vector<TypeOut> os;

   template <typename ... It, typename ... Ot>
   MyObject (std::tuple<It...> && ti, std::tuple<Ot...> && to)
    : is{ std::apply([](auto && ... ts){
                        return std::vector<TypeIn>{
                           std::forward<decltype(ts)>(ts)... }; }, ti) },
      os{ std::apply([](auto && ... ts){
                        return std::vector<TypeOut>{
                           std::forward<decltype(ts)>(ts)... }; }, to) }
    { }

   template <typename ... Ts>
   MyObject (Ts && ... ts)
    : MyObject{std::tuple_cat( filterVal<TypeIn>(std::forward<Ts>(ts)) ... ),
               std::tuple_cat( filterVal<TypeOut>(std::forward<Ts>(ts)) ... )}
    { }
 };

int main ()
 {
   TypeIn   a, b, c, d;
   TypeOut  e, f;

   MyObject mo{ a, b, c, d, e, f };

   std::cout << mo.is.size() << " TypeIn vals\n"
             << mo.os.size() << " TypeOut vals\n";
 }

Я повторяю: просто для удовольствия.

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

После прочтения комментариев и предоставленного ответа, а также из-за характера самого языка, я пришел к выводу, что, поскольку число типов фиксировано и известно, но их количество не соответствует шаблонам, быть обязательным ... Он может просто перейти к базовому c классу с простым конструктором и переместить семантику, используя initialize_list.

class In{...};
class Out{...};

class MyObject {
private:
     std::vector<In> inputs_;
     std::vector<Out> outputs_;

public:
     MyObject(initializer_list<In> inputs, initializer_list<Out> outputs ) :
       inputs_( std::move(inputs) ),
       outputs_( std::move(outputs) )
     {}
};

Редактировать - я не был Точно пытаясь показать код, который будет компилироваться, это было не просто для иллюстрации, но я исправил его для правильного соответствия будущим читателям.

...