ARTICLE AD BOX
I have a class that I'm using across a somewhat large project, and it has a set of functions which need to take, as one argument, an array-like argument full of integral values. The size of the array has to match a template parameter in the class. Here's a simplified analog:
template<std::size_t N> struct mystruct { void func(const std::array<std::size_t,N>&) { // code } }; int main() { mystruct<2> ms; ms.func({1,2}); return 0; }This compiles without issue. However, if I do something like this:
int n = 3; ms.func({n,n});I get a warning
warning: narrowing conversion of ‘n’ from ‘int’ to ‘long unsigned int’ [-Wnarrowing]Fair enough. I think this warning should be taken seriously, and I do not want to use the -Wnarrowing option globally. Does anyone know if this warning can be turned off for just one function?
If I try this, I avoid that warning:
void func(const std::array<int,N>&) { // code with range check }But then this code
mystruct<2> ms; std::vector<double> v; ms.func({v.size(),v.size()});triggers this warning
warning: narrowing conversion of ‘v.std::vector<double>::size()’ from ‘std::vector<double>::size_type’ {aka ‘long unsigned int’} to ‘int’ [-Wnarrowing]As it should. size_t and int have ranges that don't fully overlap. So, how about an overload for each?
template<std::size_t N> struct mystruct { void func(const std::array<std::size_t,N>&) { // code } void func(const std::array<int,N>&) { // code with range check } };This is worse, since int and size_t can be converted, and we now get an ambiguity error:
error: call of overloaded ‘func(<brace-enclosed initializer list>)’ is ambiguousWhat about initializer_lists?
template<typename T> void func(const std::initializer_list<T>&) { // check that the list's size matches N // code with range check }That actually works in the above examples, but fails in the mixed case
mystruct<2> ms; std::vector<double> v; ms.func({3,v.size()});With the error
error: no matching function for call to ‘mystruct<2>::func(<brace-enclosed initializer list>)’ test.cpp:18:29: note: template argument deduction/substitution failed: test.cpp:33:12: note: deduced conflicting types for parameter ‘_Tp’ (‘int’ and ‘long unsigned int’)Here's another idea I tried:
template<typename... Args> void func(const std::tuple<Args...>&) { // check that the tuple's size matches N // code with range check }But that produces
error: cannot convert ‘<brace-enclosed initializer list>’ to ‘const std::tuple<>&’Any ideas? This class is part of a larger project, and these are all common use cases. One solution would be to do a range check at each point the function is called, and then static_cast the values to the right times. But, that would get cumbersome really fast.
