1

Given the following, how can I correctly construct an object of an unknown type from a parameter pack?

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

I expect the template function to only be called with matching types, so everything in the parameter pack should be of the same type. It doesn't matter which individual item I reference if I need to use decltype, for example (relevant code in the commented out section will cause compilation errors otherwise).

cigien
  • 57,834
  • 11
  • 73
  • 112
cbrng
  • 63
  • 4
  • 2
    And if the parameter pack is empty, what object do you expect to be created? An `int`? A `bool`?. And if the function requires at least one parameter, just declare a function with one template parameter and a possibly empty parameter pack, and just use the first parameter's type, directly. – Sam Varshavchik Dec 08 '21 at 22:35
  • @SamVarshavchik easy fix ```static_assert( sizeof...( pack ) > 1 );```. Also I had considered that possibility but lets ignore it for now and just answer the question as is. Assume use in another scenario. – cbrng Dec 08 '21 at 23:06

3 Answers3

1

Here is one way (assuming we are talking about relatively simple types, which can sustain copying):

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

Here is another, more convoluted, but working way, which puts no additional limitation on types:

#include <tuple>

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

    // Do stuff with result
    return result;
}


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

auto z = foo(10); // z is 0-initialized int
SergeyA
  • 61,605
  • 5
  • 78
  • 137
1

Since all the types in the parameter pack are the same, you can first use the comma operator to expand the parameter pack, then use decltype to get the type of the last operand.

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

Demo.

cigien
  • 57,834
  • 11
  • 73
  • 112
康桓瑋
  • 33,481
  • 5
  • 40
  • 90
0

Since all the types in the parameter pack are the same, you can use std::common_type_t, which gives a type that all the types in the parameter pack can be converted to.

template <typename... Types>
auto foo(Types&&... types) {
    auto result = std::common_type_t<Types...>{};
    // Do stuff with result
    return result;
}
cigien
  • 57,834
  • 11
  • 73
  • 112