Reputation: 694
I'm new to C++ and I am not sure the best way to model a class to represent a table of columns; where a column is wrapper around a STL vector with a name (string) and should either be
Column<int>
, Column<float>
or Column<std::string>
.
At the moment I have hardcoded it to Column<int>
but need to support Column<float>
or Column<std::string>
.
Should I go down the boost variant route (aka tagged union)?
boost::variant<Column<int>*, Column<float>*, Column<std::string>*>
Not sure if there's a better solution since it just the type parameter that is different.
I would be grateful to the C++ gods to share their wisdom.
template <typename T>
class Column
{
public:
Column(std::string& name, std::vector<T>& vec) : name(name), vec(vec) {}
T& at(const size_t i) { return vec[i]; }
private:
std::string name;
std::vector<T> vec;
};
class Table
{
public:
Table(std::string& name) : name{name} {}
void addColumn(Column<int>* vec)
{
columns.push_back(vec);
}
Column<int>*& getColumn(const size_t i)
{
return columns[i];
}
private:
std::string name;
std::vector<Column<int>*> columns;
};
Upvotes: 3
Views: 591
Reputation: 393134
If a variant is appropriate for your use case: sure! The template instances are just types.
You might be able to switch the design to something more like
Column<boost::variant<int, float, std::string>>
instead though
You can generate a variant from a typelist:
column_variant<int, float, std::string>
In c++11 this is rather trivial:
template <typename... Ts>
using make_column_variant = typename boost::make_variant_over<boost::mpl::vector<Column<Ts>...>>::type;
Here's a c++03 version of that:
#include <boost/variant.hpp>
#include <boost/mpl/vector.hpp>
#include <iostream>
template <typename T> struct Column {
T v;
Column(T const& v) : v(v) {}
friend std::ostream& operator<<(std::ostream& os, Column<T> const& cv) {
return os << cv.v;
}
};
/* c++03 helper */
namespace mpl = boost::mpl;
template <typename Seq>
struct make_column_variant
{
typedef typename mpl::transform<
Seq,
Column<mpl::_1>,
mpl::back_inserter<mpl::vector<> >
>::type columns;
typedef typename boost::make_variant_over<columns>::type type;
};
int main() {
make_column_variant<mpl::vector<int, float, std::string> >::type v(std::string("hello world"));
std::cout << v;
}
This can be considerably shorter in C++11
Upvotes: 1
Reputation: 249293
Yes, using Boost.Variant is reasonable for this. However, you don't need to use pointers at all; instead:
boost::variant<Column<int>, Column<float>, Column<std::string>>
Upvotes: 1