Аргументы конструктора из кортежа

c++ struct constructor tuples

1763 просмотра

6 ответа

1060 Репутация автора

Если у меня есть структура, как:

struct Thing
{
  int x;
  int y;
  bool a;
  bool b;
}

Тогда я могу создать Thingобъект, выполнив: Thing t {1,2,true,false};. Однако, если у меня есть кортеж, я делаю что-то вроде:

std::tuple<int, int, bool, bool> info = std::make_tuple(1,2,true,false);
Thing t { std::get<0>(info), std::get<1>(info).. // and so on

Есть лучший способ сделать это?

Автор: Addy Источник Размещён: 18.07.2016 03:40

Ответы (6)


1 плюс

3926 Репутация автора

Предоставьте явный конструктор и оператор присваивания:

struct Thing
{
  int x;
  int y;
  bool a;
  bool b;

  Thing() { }

  Thing( int x, int y, bool a, bool b ): x(x), y(y), a(a), b(b) { }

  Thing( const std::tuple <int, int, bool, bool> & t ) 
  {
    std::tie( x, y, a, b ) = t;
  }

  Thing& operator = ( const std::tuple <int, int, bool, bool> & t ) 
  {
    std::tie( x, y, a, b ) = t;
    return *this;
  }
};

Надеюсь это поможет.

Автор: Dúthomhas Размещён: 18.07.2016 03:49

3 плюса

134457 Репутация автора

Вы можете использовать std::tie:

Thing t;

std::tie(t.x, t.y, t.a, t.b) = info;
Автор: Jarod42 Размещён: 18.07.2016 03:49

1 плюс

3232 Репутация автора

Вот другие способы:

struct Thing
{
    Thing(){}

    Thing(int A_, int B_, int C_, int D_) //1
        : A(A_), B(B_), C(C_), D(D_) {}

    Thing(std::tuple<int,int,bool,bool> tuple) //3
        : A(std::get<0>(tuple)), B(std::get<1>(tuple)),
          C(std::get<2>(tuple)), D(std::get<3>(tuple)) {}

    void tie_from_tuple(std::tuple<int,int,bool,bool> tuple) //4
    {
        std::tie(A,B,C,D) = tuple;
    }

    int A;
    int B;
    bool C;
    bool D;
};

inline Thing tuple_to_thing(const std::tuple<int,int,bool,bool>& tuple) //2
{
    return Thing{std::get<0>(tuple), std::get<1>(tuple),
                 std::get<2>(tuple), std::get<3>(tuple)};
}

int main()
{
    auto info = std::make_tuple(1,2,true,false);

    //1 make a constructor
    Thing one(info);
    //2 make a conversion function
    Thing second = tuple_to_thing(info);
    //3 don't use tuple (just use the struct itself if you have to pass it)
    Thing three{1,2,true,false};
    //4 make member function that uses std::tie
    Thing four;
    four.tie_from_tuple(info);
}
Автор: xinaiz Размещён: 18.07.2016 04:00

4 плюса

9997 Репутация автора

Если вы используете c ++ 14, вы можете std::index_sequenceсоздать вспомогательную функцию и структуру следующим образом:

#include <tuple>
#include <utility>

struct Thing
{
  int x;
  int y;
  bool a;
  bool b;
};

template <class Thi, class Tup, class I = std::make_index_sequence<std::tuple_size<Tup>::value>>
struct Creator;

template <class Thi, class Tup, size_t... Is>
struct Creator<Thi, Tup, std::index_sequence<Is...> > {
   static Thi create(const Tup &t) {
      return {std::get<Is>(t)...};
   }
};

template <class Thi, class Tup>
Thi create(const Tup &t) {
   return Creator<Thi, Tup>::create(t);
}

int main() {
   Thing thi = create<Thing>(std::make_tuple(1,2,true,false));
}

И версия без дополнительного класса (с одной дополнительной функцией):

#include <tuple>
#include <utility>

struct Thing
{
  int x;
  int y;
  bool a;
  bool b;
};

template <class Thi, class Tup, size_t... Is>
Thi create_impl(const Tup &t, std::index_sequence<Is...>) {
   return {std::get<Is>(t)...};
}

template <class Thi, class Tup>
Thi create(const Tup &t) {
   return create_impl<Thi, Tup>(t, std::make_index_sequence<std::tuple_size<Tup>::value>{});
}

int main() {
   Thing thi = create<Thing>(std::make_tuple(1,2,true,false));
}

Еще одна хитрая на этот раз версия с одной вспомогательной функцией:

#include <tuple>
#include <utility>

struct Thing
{
  int x;
  int y;
  bool a;
  bool b;
};

template <class R, class T, size_t... Is>
R create(const T &t, std::index_sequence<Is...> = {}) {
   if (std::tuple_size<T>::value == sizeof...(Is)) {
      return {std::get<Is>(t)...};
   }
   return create<R>(t, std::make_index_sequence<std::tuple_size<T>::value>{});
}

int main() {
   Thing thi = create<Thing>(std::make_tuple(1,2,true,false));
}
Автор: W.F. Размещён: 18.07.2016 04:08

6 плюса

202432 Репутация автора

Мы можем создать общую функцию фабрики для создания агрегатов из кортежа-подобные типам ( std::tuple, std::pair, std::array, и произвольно определяемый пользователь кортежа как объекты в структурированных привязках мире ):

template <class T, class Tuple, size_t... Is>
T construct_from_tuple(Tuple&& tuple, std::index_sequence<Is...> ) {
    return T{std::get<Is>(std::forward<Tuple>(tuple))...};
}

template <class T, class Tuple>
T construct_from_tuple(Tuple&& tuple) {
    return construct_from_tuple<T>(std::forward<Tuple>(tuple),
        std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{}
        );
}

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

std::tuple<int, int, bool, bool> info = std::make_tuple(1,2,true,false);
Thing t = construct_from_tuple<Thing>(info); // or std::move(info)

Таким образом, он Thingвсе еще может быть агрегатом (не нужно добавлять конструктор / назначения), и наше решение решает проблему для многих, многих типов.

В качестве улучшения мы могли бы добавить SFINAE к обеим перегрузкам, чтобы гарантировать, что они не будут вызываться с недопустимыми типами кортежей.


В ожидании принятия формулировки о том, как будет работать декомпозиция, квалифицированный вызов, std::get<Is>возможно, придется заменить на неквалифицированный вызов, для get<Is>которого есть специальные правила поиска. На данный момент это спорный вопрос, поскольку сейчас 2016 год, и у нас нет структурированных привязок.


Обновление: в C ++ 17 есть std::make_from_tuple().

Автор: Barry Размещён: 18.07.2016 04:16

1 плюс

408 Репутация автора

Придумываете вычитание аргументов шаблона C ++ 17 и использование прокси-объекта (пример использования внизу):

#include <tuple>

using namespace std;

template <class Tuple>
class FromTuple {
    // static constructor, used to unpack argument_pack
    template <class Result, class From, size_t... indices>
    static constexpr Result construct(index_sequence<indices...>, From&& from_tuple) {
        return { get<indices>(forward<
                decltype(from_tuple.arguments)>(from_tuple.arguments))... };
    }

    // used to select static constructor
    using Indices = make_index_sequence<
            tuple_size_v< remove_reference_t<Tuple> >>;

public:
    // construct with actual tuple types only for parameter deduction
    explicit constexpr FromTuple(const Tuple& arguments) : arguments(arguments) {}
    explicit constexpr FromTuple(Tuple&& arguments) : arguments(move(arguments)) {}

    // implicit cast operator delegates to static constructor
    template <class Result>
    constexpr operator Result() { return construct<Result>(Indices{}, *this); }

private:
    Tuple arguments;
};

struct Thing { int x; int y; bool a; bool b; };

int main() {
    std::tuple<int, int, bool, bool> info = std::make_tuple(1,2,true,false);

    Thing thing0((Thing)FromTuple(info));
    Thing thing1{(Thing)FromTuple(info)};

    FromTuple from_info(info);
    Thing thing2(from_info); // only way to avoid implicit cast operator
    Thing thing3{(Thing)from_info};

    return 0;
}

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

Автор: Taylor Nichols Размещён: 03.08.2018 12:33
Вопросы из категории :
32x32