Как можно создать объект из пакета параметров в шаблоне C ?

#c #templates #c 17 #parameter-pack

#c #шаблоны #c 17 #parameter-pack

Вопрос:

Учитывая следующее, как я могу правильно создать объект неизвестного типа из пакета параметров?

 template < typename... Types >
auto foo( Typesamp;amp;... types ) {
    auto result =  Types{ }; // How should this be done?
    // Do stuff with result
    return resu<
}
 

Я ожидаю, что функция шаблона будет вызываться только с соответствующими типами, поэтому все в пакете параметров должно быть одного типа. Не имеет значения, на какой отдельный элемент я ссылаюсь, если мне нужно использовать decltype , например (соответствующий код в разделе с комментариями в противном случае вызовет ошибки компиляции).

Комментарии:

1. И если пакет параметров пуст, какой объект вы ожидаете создать? An int ? A bool ?. И если для функции требуется хотя бы один параметр, просто объявите функцию с одним параметром шаблона и, возможно, пустым пакетом параметров и просто используйте тип первого параметра напрямую.

2. @SamVarshavchik простое исправление static_assert( sizeof...( pack ) > 1 ); . Также я рассматривал эту возможность, но давайте пока проигнорируем ее и просто ответим на вопрос как есть. Предположим, что он используется в другом сценарии.

Ответ №1:

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

 template<typename... Types>
auto foo(Typesamp;amp;... types) {
  auto result = decltype((Types{}, ...)){ };
  // Do stuff with result
  return resu<
}
 

ДЕМОНСТРАЦИЯ.

Ответ №2:

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

 template < typename... Types >
auto foo( Typesamp;amp;... types ) {
    return std::array{types...}[0];
}
 

Вот другой, более сложный, но работающий способ, который не накладывает дополнительных ограничений на типы:

 #include <tuple>

template < typename... Types >
auto foo( Typesamp;amp;... types ) {
    using tup_t = std::tuple<Types...>;
    auto result =  std::tuple_element_t<0, tup_t>{}; 

    // Do stuff with result
    return resu<
}


// auto k = foo(); // compile error

auto z = foo(10); // z is 0-initialized int
 

Комментарии:

1. Интересная работа, возможно, придется пойти на это, если никто другой не предложит более прямое решение. Спасибо!

2. @cbrng добавил еще один

Ответ №3:

Поскольку все типы в пакете параметров одинаковы, вы можете использовать std::common_type_t , который дает тип, в который могут быть преобразованы все типы в пакете параметров.

 template <typename... Types>
auto foo(Typesamp;amp;... types) {
    auto result = std::common_type_t<Types...>{};
    // Do stuff with result
    return resu<
}