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) ?
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.