Переменные-члены шаблона в зависимости от правил - PullRequest
2 голосов
/ 17 апреля 2019

в следующем коде:

#include <iostream>
#include <tuple>

template<typename T>
struct Container
{
  std::string id;
  T value;

  Container(std::string id, T value) : id(id), value(value) {}
};

template<typename... T>
struct ElementCodec
{
  std::tuple<T...> values;

  ElementCodec(T... args) : values(args...) {}
};

template<typename... T> ElementCodec(T...) -> ElementCodec<T...>;

int main()
{
  ElementCodec a { int { 5 }, double { 3. }, Container { "52", 7 } };
  auto [x, y, container] = a.values;

  std::cout << x << ", " << y << ", " << container.value << '\n';

}

После специализации данного кода кортеж values имеет тип std::tuple<int, double, Container<int>>.То, что я хотел бы сделать, это уменьшить его до типа, хранящегося в контейнере, поэтому std::tuple<int, double, int>, чтобы сделать th-доступ через container.value необязательным.

Возможно ли это сделать в c ++ 17?Я застрял в этой проблеме некоторое время и не могу найти никаких ресурсов по этому поводу.

1 Ответ

7 голосов
/ 17 апреля 2019

Вы можете развернуть Container<T> s с помощью вспомогательной функции:

template <typename T> T unwrap(T value)        { return value; }
template <typename T> T unwrap(Container<T> c) { return c.value; }

template <typename T> using unwrap_t = decltype(unwrap(std::declval<T>()));

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

template <typename... T>
struct ElementCodec
{
  std::tuple<T...> values;

  template <typename... Us>
  ElementCodec(Us... args) : values(unwrap(args)...) {}
};

template<typename... T>
ElementCodec(T...) -> ElementCodec<unwrap_t<T>...>;

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

template <typename... Us,
  std::enable_if_t<std::is_constructible_v<
    std::tuple<T...>, unwrap_t<Us>...
    >, int> = 0>
ElementCodec(Us... args) : values(unwrap(args)...) {}
...