Suppose we are given a C++ vector. We want to specify a variable amount of indices and select elements from a vector being indexed. I have two implementation: (A) one relies on C++11 initializer lists, and the second one (B) on va_list
and macro mess. Arrangement B is however funkier to type because it requires no typing the braces comprising the initializer list.
So my main question is: which one should an adult C++ programmer use, if any?
coderodde.h:
#ifndef CODERODDE_H
#define CODERODDE_H
#include <cstdarg>
#include <iostream>
#include <vector>
#define NUM_ARGS(...) (sizeof((size_t[]){__VA_ARGS__}) / sizeof(size_t))
namespace coderodde {
template<class T>
std::vector<T> select(const std::vector<T>& vec,
const std::vector<size_t>& indices)
{
std::vector<T> ret;
for (auto index : indices) {
ret.push_back(vec.at(index));
}
return ret;
}
template<class T>
std::vector<T> select(const std::vector<T>& vec, const size_t len, ...)
{
std::va_list ap;
std::vector<T> ret;
va_start(ap, len);
for (size_t i = 0; i < len; ++i)
{
ret.push_back(vec.at(va_arg(ap, size_t)));
}
va_end(ap);
return ret;
}
}
#define SELECT(vec, ...) (select(vec, NUM_ARGS(__VA_ARGS__), __VA_ARGS__))
#endif // CODERODDE_H
The test driver main.cpp:
#include <iostream>
#include <string>
#include <vector>
#include "coderodde.h"
using std::cout;
using std::endl;
using std::string;
using std::vector;
using coderodde::select;
void test_smart(const vector<string>& input)
{
const size_t N = input.size();
for (size_t ca = 0; ca < N; ++ca)
{
for (size_t cb = 0; cb < N; ++cb)
{
for (size_t cc = 0; cc < N; ++cc)
{
for (auto s : select(input, { ca, cb, cc }))
{
cout << s;
}
cout << endl;
}
}
}
}
void test_stupid(const vector<string>& input)
{
const size_t N = input.size();
for (size_t ca = 0; ca < N; ++ca)
{
for (size_t cb = 0; cb < N; ++cb)
{
for (size_t cc = 0; cc < N; ++cc)
{
for (auto s : SELECT(input, ca, cb, cc))
{
cout << s;
}
cout << endl;
}
}
}
}
int main(int argc, char** argv)
{
std::vector<std::string> string_vec {"A", "B", "C", "D"};
cout << "Smart:" << endl;
test_smart(string_vec);
cout << "Stupid:" << endl;
test_stupid(string_vec);
return 0;
}