In one of my projects I'm actively using boost::variant
and I stumbled upon a question I couldn't resolve on my own. I have a boost::variant
that might contain atomic datatypes and STL containers of these atomic datatypes.
Now, I wanted to compute the size of an instance of the previously defined boost::variant
type. There are basically only two possible functions. The type of an atomic datatype is simply 1, whereas the size of an STL container is defined as the number of elements contained in it.
Having only 2 atomic dataypes I implemented the following code:
#include <boost/variant.hpp>
#include <string>
#include <iostream>
#include <vector>
typedef boost::variant<int, double, std::vector<int>, std::vector<double> > TVariant;
struct sizeVisitor : boost::static_visitor<size_t> {
size_t operator()(int&) {
return 1;
}
size_t operator()(double&) {
return 1;
}
size_t operator()(std::vector<int>& c) {
return c.size();
}
size_t operator()(std::vector<double>& c) {
return c.size();
}
} ;
int main(int argc, char **args) {
sizeVisitor visitor;
TVariant var=5;
std::cout << boost::apply_visitor(visitor, var) << std::endl;
std::vector<int> vector;
vector.push_back(6);
vector.push_back(2);
var=vector;
std::cout << boost::apply_visitor(visitor, var) << std::endl;
}
As the number of atomic datatypes increases I have a lot of code duplication. I have to declare another two functions for every new atomic datatype, which can be prohibitive.
It would be nice, if the following code would compile:
#include <boost/variant.hpp>
#include <string>
#include <iostream>
#include <vector>
typedef boost::variant<int, double, std::vector<int>, std::vector<double> > TVariant;
struct sizeVisitor : boost::static_visitor<size_t> {
size_t operator()(boost::variant<int,double>&) {
return 1;
}
size_t operator()(boost::variant<std::vector<int>,std::vector<double>>& c) {
return c.size();
}
} ;
int main(int argc, char **args) {
sizeVisitor visitor;
TVariant var=5;
std::cout << boost::apply_visitor(visitor, var) << std::endl;
std::vector<int> vector;
vector.push_back(6);
vector.push_back(2);
var=vector;
std::cout << boost::apply_visitor(visitor, var) << std::endl;
}
What might be the closest implementation of the second, unfortunately non-compiling, visitor?
Just use two function templates for operator()
:
struct sizeVisitor
: boost::static_visitor<size_t>
{
template <class T>
size_t operator()(T const&) {
return 1;
}
template <class T>
size_t operator()(std::vector<T> const& v) {
return v.size();
}
};
The template partial ordering rules will ensure that the correct one is called.