2

I am trying to construct a class having using variadic template constructor. The template arguments are all the same type.

I am using Visual C++ compiler with C++ 17, but code does not build; this code is actually crashing the compiler.

Is that possible in C++17 ?

 struct Alfa {
     template<int... T>
     Alfa(const T&... all_args) {
         std::tuple<T...> data(all_args...);       
     }    
 };

 Alfa alfa(1,2,3,4);
max66
  • 65,235
  • 10
  • 71
  • 111
Abruzzo Forte e Gentile
  • 14,423
  • 28
  • 99
  • 173

2 Answers2

3

The template arguments are all the same type. [...] is that possible in C++17 ?

Yes, it's possible.

But non in a so simple way and with some drawbacks.

You can write a constructor accepting arguments of different type; this is simple

 template <typename ... Ts>
 Alfa (const Ts & ... as) 
  { std::tuple<Ts...> data{as...}; } 

but this permit that the Ts... types are different.

You can impose that all types are the same, using SFINAE, as follows

 template <typename T, typename ... Ts,
           std::enable_if_t<(std::is_same_v<T, Ts> && ...), bool> = true>
 Alfa (T const & a0, Ts const & ... as)
  {
     std::tuple<T, Ts...> data0{a0, as...};       
     std::array           data1{a0, as...};
  }  

so your constructor is enabled only if all Ts... types, following the first T, are exactly the same as T

Drawback: works with

   Alfa alfa{1, 2, 3, 4};

but gives an error with

   Alfa alfa{1l, 2l, 3, 4l};  <-- 3 isn't long

because 3 is convertible to long (1l is long) but isn't long.

So you can check if the following Ts... are convertible to T, instead if they are equals

 template <typename T, typename ... Ts,
           std::enable_if_t<(std::is_convertible_v<Ts, T> && ...), bool> = true>
 Alfa (T const & a0, Ts const & ... as)
  {
     std::tuple<T, Ts...>             data0{a0, as...};       
     std::array<T, sizeof...(Ts)+1u>  data1{a0, as...};
  }   

but this way you give to T a bigger importance to other types (works if all Ts... are convertible to T but not if T is convertible to one of the Ts...) so I suppose that the better solution is check if there is a common type

 template <typename ... Ts,
           typename CT = std::common_type_t<Ts...>>
 Alfa (Ts const & ... as)
  {
     std::tuple<Ts...>              data0{as...};       
     std::array<CT, sizeof...(Ts)>  data1{as...};
  }  
max66
  • 65,235
  • 10
  • 71
  • 111
1

You have to decide whether you want non-type template arguments or not. Your code first says "the T are integer values", but then tries to use the T like a type in the function signature and tuple template argument list.

Valid options would be:

 struct Alfa {
     template<class ... Ts>
     Alfa(const Ts&... all_args) {
         std::tuple<Ts...> data(all_args...);       
     }    
 };

 Alfa alfa(1,2,3,4);

This doesn't encode the constraint of "all Ts have to be the same". There's no direct way to do that. You could use static_assert or SFINAE (see the other answer).

 template<int... Is>
 struct Alfa {
     Alfa() {
         std::tuple data(Is...); // Using class template argument deduction.
     }    
 };

 Alfa<1,2,3,4> alfa{};

This templates the class, not the constructor, which is most likely not what you want. It shows the syntax for accepting compile-time integer values (i.e. a non-type template parameter pack). But you cannot use deduction for non-type template parameters, so they have to be specified explicitly. But that's impossible for the constructor!

A compromise might be:

 struct Alfa {
     template<class ... Ts>
     Alfa(const Ts&... all_args) {
         std::tuple<Ts...> data(all_args...);       
     }    
 };

 template<int ... Is>
 auto makeAlfa() { return Alfa(Is...); }

 Alfa alfa = makeAlfa<1,2,3,4>();
Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • That's true. When I coded using template parameter T I did try lots of trial and error to make my example work. I like the suggestion about 'static_assert' which comes very handy and I find it stylish as well. Thanks a lot for your response which solves as well my issue. – Abruzzo Forte e Gentile Jan 22 '20 at 10:01