Reputation: 3784
I'm trying to find a good solution for the following problem:
I want to implement a function that takes a variable number of container arguments and returns the size of the biggest container. Here is an example:
std::vector<std::string> vStr(2, "foo");
std::vector<int> vInt(1, 123);
std::vector<double> vDouble(3, 1.1);
std::list<char> lChar(4, '*');
// or even more container
size_t uiMaxSize = getMaxContainerSize(vStr, vInt, vDouble, lChar /*, ...*/);
in this case getMaxContainerSize
should return 4, because lChar
has the biggest size of 4.
I've already implemented this workaround using cstdarg
:
#include <cstdarg>
...
size_t getMaxContainerSize(int iCnt, ... )
{
size_t uiMaxSize = 0;
va_list ap;
va_start(ap, iCnt);
for(int i=0; i<iCnt; i++)
{
size_t uiTempSize = va_arg(ap, size_t);
uiMaxSize = uiMaxSize<uiTempSize ? uiTempSize : uiMaxSize;
}
va_end(ap);
return uiMaxSize;
}
...
size_t uiMaxSize = getMaxContainerSize( 4, vStr.size(), vInt.size(), vDouble.size(), lChar.size());
But with this I have to type .size()
for every container and I also have to specify the number of containers. I also don't like to use C stuff in C++ programs and I'm asking myself if there is a better way to implement this. Maybe by using some class and overloading operator<<()
so I can type something like this:
MaxSizeFinder cFinder;
cFinder << vStr << vInt << vDouble << lChar;
size_t uiMaxSize = cFinder.getResult();
Do you think something like this is possible? Any suggestions?
Thank you.
Upvotes: 1
Views: 801
Reputation: 61970
Use a variadic template:
template<typename... Conts>
std::ptrdiff_t getMaxContainerSize(const Conts&... conts) {
return std::max({conts.size()...});
}
When you pass containers as arguments, the compiler will deduce a list of types for Conts
. Each parameter of the function will be a const <deduced type> &
*. Using conts.size()...
expands to conts1.size(), conts2.size(), ..., contsN.size()
, where conts#
is each argument given to the function. It turns out std::max
has a handy overload that you can delegate this to.
There are a couple key advantages of variadic templates over C variadic functions:
sizeof...(Conts)
.char
would be an int
by the time the function has to pick it out, among others.printf
's format specifiers).Finally, per the comments, the return type was changed to a signed type that mostly acts as the signed counterpart to size_t
(sort of like the non-standard ssize_t
).
To future-proof the answer, there will soon be a std::size
for a more generic way to get a container's size:
using std::size;
return std::max({size(conts)...});
This expands similar to above: size(conts1), size(conts2), ..., size(contsN)
*Normally, parameter packs are used with T&&...
with std::forward
instead of const T&...
. This would potentially buy you something with third-party classes that have a more efficient size
function when the object used is an rvalue. However, it adds complexity in general for a low chance at any benefit.
Upvotes: 7