variadic template method to create object

I have a variadic template method inside a template class (of type T_) looking like this

template < typename T_ >
class MyContainer {
  public:
  
  ...
  template <typename ...A>
  ulong add (A &&...args) 
  {
    T_ t{args...};
    // other stuff ...
    vec.push_back(t);
    // returning an ulong 
  }
}

So basically I’m trying to make this class adapt to whatever type T_ but since I can’t know in advance which types its constructor requires, I use a variadic. I took inspiration from the emplace_back method from the stl library.

Nevertheless, I get a warning of narrowing conversion with integer types if I try to do something like this

MyContainer<SomeClassRequiringAnUlong> mc;
mc.add(2);
warning: narrowing conversion of ‘args#0’ from ‘int’ to ‘long unsigned int’ [-Wnarrowing]

So I was wondering if I can do anything about it. Is there any way to tell the method which parameters’ type it is supposed to take according to the template parameter T_ (which is known when the object is created) ?

Answer

Is there any way to tell the method which parameters’ type it is supposed to take according to the template parameter T_ (which is known when the object is created)?

In your case, you should use direct initialization(()) instead of list initialization({}) (to avoid unnecessary narrowing checks).

Consider the case where T is a vector<int>:

MyContainer<std::vector<int>> mc;
mc.add(3, 0);

What do you expect mc.add(3, 0) to do? In your add() function, T_ t{args...} will invoke vector<int>{3,0} and create a vector of size 2, which is obviously wrong. You should use T_ t(args...) to call the overload of vector(size_type count, const T& value) to construct a vector of size 3, just like emplace_back() does.

It is worth noting that due to P0960R3, T_ t(std::forward<Args>(args)...) can also perform aggregate initialization if T_ is aggregate.