boost::fusion::map allows duplicate keys - c++

According to the boost::fusion::map docs:
A map may contain at most one element for each key.
In practice, it is easy to violate this.
I am able to define the following type:
using map_type = fusion::map<
fusion::pair<int, char>
, fusion::pair<int, char>
, fusion::pair<int, char>>;
and instantiate it with these duplicate keys:
map_type m(
fusion::make_pair<int>('X')
, fusion::make_pair<int>('Y')
, fusion::make_pair<int>('Z'));
Iterating over the map using fusion::for_each shows the data structure does indeed contain 3 pairs, and each of the keys is of type int:
struct Foo
{
template<typename Pair>
void operator()(const Pair& p) const
{
std::cout << typeid(typename Pair::first_type).name() << "=" << p.second << '\n';
}
};
fusion::for_each(m, Foo {});
Output:
i=X
i=Y
i=Z
I would have expected a static_assert on key uniqueness, but this is obviously not the case.
Why is this?
How can I ensure that no one can instantiate a fusion::map with duplicate keys?
Full working example: (on coliru)
#include <boost/fusion/container.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <iostream>
namespace fusion = ::boost::fusion;
struct Foo
{
template<typename Pair>
void operator()(const Pair& p) const
{
std::cout << typeid(typename Pair::first_type).name() << "=" << p.second << '\n';
}
};
int main()
{
using map_type = fusion::map<
fusion::pair<int, char>
, fusion::pair<int, char>
, fusion::pair<int, char>>;
map_type m(
fusion::make_pair<int>('X')
, fusion::make_pair<int>('Y')
, fusion::make_pair<int>('Z'));
fusion::for_each(m, Foo {});
return 0;
}
Due to comments below, here are some further details on what I'm actually trying to achieve.
The idea is to automatically generate FIX serialisation code.
A given field type can only exist once in any given FIX message - hence wanting the static_assert
Motivating example: (on coliru)
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/mpl/transform.hpp>
#include <iostream>
namespace fusion = ::boost::fusion;
namespace mpl = ::boost::mpl;
template<class Field>
struct MakePair
{
using type = typename fusion::result_of::make_pair<Field, typename Field::Type>::type;
};
template<class Fields>
struct Map
{
using pair_sequence = typename mpl::transform<Fields, MakePair<mpl::_1>>::type;
using type = typename fusion::result_of::as_map<pair_sequence>::type;
};
///////////////////////////
template<typename... Fields>
class Message
{
public:
template<class Field>
void set(const typename Field::Type& val)
{
fusion::at_key<Field>(_fields) = val;
}
void serialise()
{
fusion::for_each(_fields, Serialiser {});
}
private:
struct Serialiser
{
template<typename Pair>
void operator()(const Pair& pair) const
{
using Field = typename Pair::first_type;
std::cout << Field::Tag << "=" << pair.second << "|";
}
};
using FieldsVector = fusion::vector<Fields...>;
using FieldsMap = typename Map<FieldsVector>::type;
FieldsMap _fields;
static_assert(fusion::result_of::size<FieldsMap>::value == fusion::result_of::size<FieldsVector>::value,
"message must be constructed from unique types"); // this assertion doesn't work
};
///////////////////////////
#define MSG_FIELD(NAME, TYPE, TAG) \
struct NAME \
{ \
using Type = TYPE; \
static const int Tag = TAG; \
};
MSG_FIELD(MsgType, char, 35)
MSG_FIELD(Qty, int, 14)
MSG_FIELD(Price, double, 44)
using Quote = Message<MsgType, Qty, Price>;
///////////////////////////
int main()
{
Quote q;
q.set<MsgType>('a');
q.set<Qty>(5);
q.set<Price>(1.23);
q.serialise();
return 0;
}

From the docs on associative containers:
... Keys are not checked for uniqueness.
As alluded to by Richard Hodges, this is likely by design
wouldn't that static_assert involve a geometric template expansion each time it was encountered?
Nonetheless, it is possible to use boost::mpl to reduce the sequence provided to the fusion::map into a unique sequence, and static_assert on the sequence lengths being the same.
First we create a struct which iterates over the list of types and creates a sequence of unique types
// given a sequence, returns a new sequence with no duplicates
// equivalent to:
// vector UniqueSeq(vector Seq)
// vector newSeq = {}
// set uniqueElems = {}
// for (elem : Seq)
// if (!uniqueElems.find(elem))
// newSeq += elem
// uniqueElems += elem
// return newSeq
template<class Seq>
struct UniqueSeq
{
using type = typename mpl::accumulate<
Seq,
mpl::pair<typename mpl::clear<Seq>::type, mpl::set0<> >,
mpl::if_<
mpl::contains<mpl::second<mpl::_1>, mpl::_2>,
mpl::_1,
mpl::pair<
mpl::push_back<mpl::first<mpl::_1>, mpl::_2>,
mpl::insert<mpl::second<mpl::_1>, mpl::_2>
>
>
>::type::first;
};
Then we change the definition of Map to use UniqueSeq::type to generate pair_sequence:
// given a sequence of fields, returns a fusion map which maps (Field -> Field's associate type)
template<class Fields>
struct Map
{
using unique_fields = typename UniqueSeq<Fields>::type;
using pair_sequence = typename mpl::transform<unique_fields, MakePair<mpl::_1>>::type;
using type = typename fusion::result_of::as_map<pair_sequence>::type;
};
So given a list of fields, we can create a fusion::vector and a fusion::map with the result of UniqueSeq<Fields>, and assert the size of each is the same:
using FieldsVector = fusion::vector<Fields...>;
using FieldsMap = typename Map<FieldsVector>::type;
static_assert(fusion::result_of::size<FieldsMap>::value == fusion::result_of::size<FieldsVector>::value,
"message must be constructed from unique types");
Passing duplicated fields now causes a compilation error:
static assertion failed: message must be constructed from unique types
scratch/main.cpp: In instantiation of ‘class Message<Qty, Price, Qty>’:
scratch/main.cpp:129:23: required from here
scratch/main.cpp:96:5: error: static assertion failed: message must be constructed from unique types
static_assert(fusion::result_of::size<FieldsMap>::value == fusion::result_of::size<FieldsVector>::value,
^
Full example on coliru

It is not an answer (OP already provided an answer), but a response to request to clarify some of my comments.
One way of achieving key uniqueness would be thrugh raw mpl usage. For example, taking FIX message as our domain, following piece of code should illustrate the idea. The code was not compiled and provided as generic illustration example only.
template <class ValueType, int FieldTag>
struct FixField {
using value_t = ValueType;
static const short tag = FieldTag;
};
using CumQty = FixField<double, 14>;
using Price = FixField<double, 44>;
using inherit = boost::mpl::inherit<boost::mpl::placeholders::_1, boost::mpl::placeholders::_2>;
template <class list>
using inherit_linearly = boost::mpl::inherit_linearly<list, inherit>::type;
template <class Members>
struct FixMessage : iherit_linearly<Members> {
using members_t = Members;
template <class T> T& get() { return static_cast<T&>(*this); } // const ver as well
};
struct ExecutionReport : public FixMessage<boost::mpl::set<CumQty, Price> > {
static constexpr char const* name = "ExecutionReport";
};
Now you have all the instrospection into execution report you want. You can easily serialize it with boost::mpl::for_each, or you can deserialze any message and get strongly-typed FixMessage.
I am not sure if you going to get a compilation error if you use the same type twice, but I am sure that you will only see the type once when iterating.

Related

Polymorphic setter for Boost::variant

I am trying to use the boost::variant with template types. For example, I have a template type Tag<T> and the boost::variant AnyTag comprises types such as Tag<double>, Tag<int> and Tag<std::string>. Each Tag<T> has members of type T.
Now, I would like to put those variants in a container and simply assign values during runtime, e.g.,
for(AnyTag & tag: AllTags) {
setValue(tag, getValueFromXml());
}
The function setValue(AnyTag &tag, T &val) must use the runtime type of the AnyTag tag in order to correctly assign the tag with the correct value.
My attempt to solving the problem can be found below and it makes use of another variant which included only the possible T types that could be used in the AnyTag (TagValueType).
template<typename T, typename = void>
class Tag {};
template <typename T>
class Tag<T, EnableIf<std::is_arithmetic<T>>> {
public:
T value = 0;
std::string address = "";
T maxValue = std::numeric_limits<T>::max();
typedef T value_type;
};
template <typename T>
class Tag<T, DisableIf<std::is_arithmetic<T>>> {
public:
T value;
std::string address = "";
typedef T value_type;
};
typedef boost::variant<Tag<std::string>,
Tag<double>,
Tag<int>,
> AnyTag;
typedef boost::variant<std::string, double, int> TagValueType;
class tag_set_value_visitor: public boost::static_visitor<void>
{
const TagValueType & value;
public:
tag_set_value_visitor(const TagValueType & val): value(val){}
template <typename T>
void operator()(T & tag) const
{
tag.value = boost::get<typename T::value_type>(value);
}
};
inline void setValue(AnyTag & tag, const TagValueType & val) {
assert(tag.which() == val.which());
boost::apply_visitor( tag_set_value_visitor(val), tag );
}
Unfortunately, this approach is not what I would like because for example during compilation there is not problem if I do the following:
AnyTag a = Tag<int>();
setValue(a, double(1.3));
but during runtime, the boost library detects the type mismatch and crashes the program.
So, my solution is kind of a type erasure that just postpones the problem.
What I would like to have is a setValue(AnyTag &tag, T &val) where T is the runtime type of the AnyTag.
I get that that's what the variant's visitor tries to do, but there is a problem in this case because when we construct the visitor we must know the type that we are going to use.
Any ideas or any thoughts about this problem?
P.S.: Sorry for the long post but I couldn't find a way to explain my thought process with fewer words.
Use¹ a binary visitor.
Implement the operator() to do nothing except for corresponding types.
Handle mismatches to taste (I return a boolean indicating success):
Live On Coliru
#include <boost/any.hpp>
#include <boost/variant.hpp>
#include <boost/mpl/vector.hpp>
#include <string>
using namespace boost;
template <typename T>
struct Tag {
T value;
};
using Types = mpl::vector<std::string, double, int>;
using Tags = mpl::transform<Types, Tag<mpl::_1> >::type;
using Variant = make_variant_over<Types>::type;
using AnyTag = make_variant_over<Tags>::type;
namespace mydetail {
struct assign_to : boost::static_visitor<bool> {
template <typename V> bool operator()(Tag<V>& tagged, V const& value) const {
tagged.value = value;
return true;
}
template <typename T, typename V> bool operator()(T&&, V&&) const {
return false;
}
};
}
bool setValue(AnyTag &tag, Variant const& val) {
return boost::apply_visitor(mydetail::assign_to(), tag, val);
}
int main() {
AnyTag t;
t = Tag<std::string>();
// corresponding type assigns and returns true:
assert(setValue(t, "yes works"));
// mismatch: no effect and returns false:
assert(!setValue(t, 42));
assert(!setValue(t, 3.1415926));
}
¹ If I understood your goal correctly. I've focused on the "What I would like to have is a setValue(AnyTag &tag, T &val) where T is the runtime type of the AnyTag." part of the request.

Copy two tuples with different sizes

I am experimenting with some tuples, and I find myself in the weird position of asking this: how can I copy two tuples that differ in their sizes? Of course, this is intended limited to the minimum length of the two tuples.
So, for instance, let's create three tuples:
std::tuple<int, char, float> a(-1, 'A', 3.14);
std::tuple<int, char, double> b = a;
std::tuple<long, int, double, char> c;
Now, a and b differ in types, and the assignment work (obviously). As for a and c the things get a little more confusing.
My first implementation failed, since I don't know how to recurse on variadic templates with a specific type, so something like this won't work:
template <class T, class U>
void cp(std::tuple<T> from, std::tuple<U> to)
{
}
template <class T, class... ArgsFrom, class U, class... ArgsTo>
void cp(std::tuple<T, ArgsFrom...> from, std::tuple<U, ArgsTo...> to)
{
std::get<0>(to) = std::get<0>(from);
// And how to generate the rest of the tuples?
}
That function won't do anything. So I've devised a second failing attempt, using not the types, but the sizes:
template<class From, class To, std::size_t i>
void copy_tuple_implementation(From &from, To &to)
{
std::get<i>(to) = std::get<i>(from);
copy_tuple_implementation<From, To, i - 1>(from, to);
}
template<>
void copy_tuple_implementation<class From, class To, 0>(From &from, To &to)
{
}
template<class From, class To>
void copy_tuple(From &from, To &to)
{
constexpr std::size_t from_len = std::tuple_size<From>::value;
constexpr std::size_t to_len = std::tuple_size<To>::value;
copy_tuple_implementation<From, To, from_len < to_len ? from_len - 1 : to_len - 1>(from, to);
}
But that won't compile. I have too many errors to display here, but the most significant ones are:
Static_assert failed "tuple_element index out of range"
No type named 'type' in 'std::__1::tuple_element<18446744073709551612, std::__1::__tuple_types<> >'
Read-only variable is not assignable
No viable conversion from 'const base' (aka 'const __tuple_impl<typename __make_tuple_indices<sizeof...(_Tp)>::type, int, int, double>') to 'const __tuple_leaf<18446744073709551615UL, type>'
The interesting part is the index out of range, and the fact that I cannot copy an element with std::get<>.
Can anyone help me in this?
Thanks!
Here's one possibility, using C++14's ready-made integer sequence template (but this is easily reproduced manually if your library doesn't include it):
#include <tuple>
#include <utility>
template <std::size_t ...I, typename T1, typename T2>
void copy_tuple_impl(T1 const & from, T2 & to, std::index_sequence<I...>)
{
int dummy[] = { (std::get<I>(to) = std::get<I>(from), 0)... };
static_cast<void>(dummy);
}
template <typename T1, typename T2>
void copy_tuple(T1 const & from, T2 & to)
{
copy_tuple_impl(
from, to,
std::make_index_sequence<std::tuple_size<T1>::value>());
}
Example:
#include <iostream>
int main()
{
std::tuple<int, char> from { 1, 'x' };
std::tuple<int, char, bool> to;
copy_tuple(from, to);
std::cout << "to<0> = " << std::get<0>(to) << "\n";
}
Another option is to use operator overloading to simulate partial-specialization of your function:
template <std::size_t N>
struct size_t_t {};
template<class From, class To, std::size_t i>
void copy_tuple_implementation(From &from, To &to, size_t_t<i>)
{
std::get<i>(to) = std::get<i>(from);
copy_tuple_implementation(from, to, size_t_t<i-1>{});
}
template<class From, class To>
void copy_tuple_implementation(From &from, To &to, size_t_t<0>)
{
std::get<0>(to) = std::get<0>(from);
}
Or you could just use a helper class:
template<class From, class To, std::size_t i>
struct CopyTuple
{
static void run(From &from, To &to)
{
std::get<i>(to) = std::get<i>(from);
CopyTuple<From,To,i-1>::run(from, to);
}
};
template<class From, class To>
struct CopyTuple<From,To,0>
{
static void run(From &from, To &to)
{
std::get<0>(to) = std::get<0>(from);
}
};
The goal here is to get a clean syntax at point of use.
I define auto_slice which takes a tuple, and auto slices it for the expression.
The intended use is
auto_slice(lhs)=auto_slice(rhs);
and it just works.
// a helper that is a slightly more conservative `std::decay_t`:
template<class T>
using cleanup_t = std::remove_cv_t< std::remove_reference_t< T > >;
// the workhorse. It holds a tuple and in an rvalue context
// allows partial assignment from and to:
template<class T,size_t s0=std::tuple_size<cleanup_t<T>>{}>
struct tuple_slicer{
T&&t;
// Instead of working directly within operators, the operators
// call .get() and .assign() to do their work:
template<class Dest,size_t s1=std::tuple_size<Dest>{}>
Dest get() && {
// get a pack of indexes, and use it:
using indexes=std::make_index_sequence<(s0<s1)?s0:s1>;
return std::move(*this).template get<Dest>(indexes{});
}
template<class Dest,size_t s1=std::tuple_size<Dest>{},size_t...is>
Dest get(std::index_sequence<is...>) && {
// We cannot construct a larger tuple from a smaller one
// as we do not know what to populate the remainder with.
// We could default construct them, I guess?
static_assert(s0>=s1,"use auto_slice on target");
using std::get;
return Dest{ get<is>(std::forward<T>(t))... };
}
// allows implicit conversion from the slicer:
template<class Dest>
operator Dest()&&{
return std::move(*this).template get<Dest>();
}
// now we are doing the assignment work. This function
// does the pack expansion hack, excuse the strangeness of the
// code in it:
template<class Src, size_t...is>
void assign(std::index_sequence<is...>,tuple_slicer<Src>&&rhs)&&{
using std::get;
int _[]={0,(void(
get<is>(std::forward<T>(t))=get<is>(std::forward<Src>(rhs.t))
),0)...};
(void)_; // remove warnings
}
// assign from another slicer:
template<class Src,size_t s1>
void operator=(tuple_slicer<Src,s1>&&rhs)&&{
using indexes=std::make_index_sequence<(s0<s1)?s0:s1>;
std::move(*this).assign(indexes{},std::move(rhs));
}
// assign from a tuple. Here we pack it up in a slicer, and use the above:
template<class Src>
void operator=(Src&& src)&&{
std::move(*this) = tuple_slicer<Src>{ std::forward<Src>(src) };
}
};
// this deduces the type of tuple_slicer<?> we need for us:
template<class Tuple>
tuple_slicer<Tuple> auto_slice(Tuple&&t){
return {std::forward<Tuple>(t)};
}
The slice is only required on whichever side is smaller, but can be done on both sides (for generic code) if required.
It also works at construction. On the right hand side, it should work with std::arrays and pairs and tuples. On the left hand side, it may not work with arrays, due to requirement to construct with {{}}.
live example
Here is the recursive solution your were originally trying to figure out:
#include <tuple>
// Limit case
template<std::size_t I = 0, typename ...From, typename ...To>
typename std::enable_if<(I >= sizeof...(From) || I >= sizeof...(To))>::type
copy_tuple(std::tuple<From...> const & from, std::tuple<To...> & to) {}
// Recursive case
template<std::size_t I = 0, typename ...From, typename ...To>
typename std::enable_if<(I < sizeof...(From) && I < sizeof...(To))>::type
copy_tuple(std::tuple<From...> const & from, std::tuple<To...> & to)
{
std::get<I>(to) = std::get<I>(from);
copy_tuple<I + 1>(from,to);
}
You do not need std::index_sequence or similar apparatus, and this
solution has two strengths that your accepted one does not:
It will compile, and do the right thing, when from is longer than to: the
excess trailing elements of from are ignored.
It will compile, and do the right thing, when either from or to is an
empty tuple: the operation is a no-op.
Prepend it to this example:
#include <iostream>
int main()
{
std::tuple<int, char> a { 1, 'x' };
std::tuple<int, char, bool> b;
// Copy shorter to longer
copy_tuple(a, b);
std::cout << "b<0> = " << std::get<0>(b) << "\n";
std::cout << "b<1> = " << std::get<1>(b) << "\n";
std::cout << "b<2> = " << std::get<2>(b) << "\n\n";
// Copy longer to shorter
std::get<0>(b) = 2;
std::get<1>(b) = 'y';
copy_tuple(b,a);
std::cout << "a<0> = " << std::get<0>(a) << "\n";
std::cout << "a<1> = " << std::get<1>(a) << "\n\n";
// Copy empty to non-empty
std::tuple<> empty;
copy_tuple(empty,a);
std::cout << "a<0> = " << std::get<0>(a) << "\n";
std::cout << "a<1> = " << std::get<1>(a) << "\n\n";
// Copy non-empty to empty
copy_tuple(a,empty);
return 0;
}
(g++ 4.9/clang 3.5, -std=c++11)

Deducing the return type of a map with varying value types

I have the following code
#include <boost\any.hpp>
#include <iostream>
#include <memory>
#include <map>
#include <string>
enum class tags { int_param, string_param };
class Parameters
{
public:
template <typename T>
void set(tags key, T value)
{
map_[key] = value;
}
template <typename T>
T get(tags key)
{
return boost::any_cast<T>(map_[key]);
}
private:
std::map<tags, boost::any> map_;
};
int main()
{
Parameters params;
params.set(tags::int_param, 42);
params.set(tags::string_param, "it works!");
int int_par = params.get<int>(tags::int_param);
std::string string_par = params.get<std::string>(tags::string_param);
std::cout << "Channel: " << int_par << std::endl;
std::cout << "Filename: " << string_par << std::endl;
}
This code works however I do not like having to supply the templated type and I would like, if at all possible, to be able to retrieve something from the map without having to supply the template type i.e.
int int_par = params.get(tags::int_param);
instead of
int int_par = params.get<int>(tags::int_param);
I understand by using boost::any that we need to cast to a supplied type from the any type but is there a way we can do it without having to supply it ourself and can we instead deduce it some other way>
If you change tags from enum values to structs you can achieve the desired behavior and even other good features, such as type safety and that our use of any_cast won't ever throw.
By using structs we can define simple traits to get each tags value type, such as
enum class tag_id
{
int_param; // Id which represents int_param tag on std::map
}
struct int_param_t
{
using value_type = int;
static const tag_id id;
};
const tag_id int_param_t::id = tag_id::int_param;
Now we can use this traits to achieve your desired syntax
template< typename Tag >
auto get( Tag ) -> typename Tag::valye_type
{
return boost::any_cast<typename Tag::valye_type>(map_[Tag::id]);
}
// ...
int a = parameters.get( int_param_t{} ); // Ok, returns int.
std::string b = parameters.get( int_param_t{} ); // Error, int is not convertible to std::string.
As a bonus we can use this traits to ensure only types convertable to the correct type are used with set function
template< typename Tag >
void set( Tag, typename Tag::value_type value )
{
map_[Tag::id] = value;
}
// ...
parameter.set( int_param_t{}, 0 ); // Ok, 0 is convertible to int.
parameter.set( int_param_t{}, "string" ); // Error, const char[] is not convertible to int.
To make it a little bit prettier, I would also define some alias and constants such as
// Helper alias to avoid writing typename everywhere.
template< typename T >
using param_type = typename T::value_type;
// Used to avoid having to create tag objects every function call.
constexpr int_param_t int_param{};
And here is the final product
#include <boost/any.hpp>
#include <iostream>
#include <memory>
#include <map>
#include <string>
namespace tags
{
enum class tag_id
{
int_param,
string_param
};
struct int_param_t
{
using value_type = int;
static const tag_id id;
};
const tag_id int_param_t::id = tag_id::int_param;
constexpr int_param_t int_param{};
struct string_param_t
{
using value_type = std::string;
static const tag_id id;
};
const tag_id string_param_t::id = tag_id::string_param;
constexpr string_param_t string_param{};
}
// Helper alias to avoid writing typename everywhere.
template< typename T >
using param_type = typename T::value_type;
class Parameters
{
public:
template <typename Tag>
void set(Tag, param_type< Tag > value)
{
map_[Tag::id] = value;
}
template <typename Tag>
auto get(Tag) -> param_type< Tag >
{
return boost::any_cast< param_type< Tag > >(map_[Tag::id]);
}
private:
std::map<tags::tag_id, boost::any> map_;
};
int main()
{
Parameters params;
params.set(tags::int_param, 42);
params.set(tags::string_param, "it works!");
int int_par = params.get(tags::int_param);
std::string string_par = params.get(tags::string_param);
std::cout << "Channel: " << int_par << std::endl;
std::cout << "Filename: " << string_par << std::endl;
}
There is no way to deduce anything from an any but there might be a chance to deduce something from the declaration. As your code already throws when any_cast fails, I suppose this is not an issue for you.
You could extend (really a bad idea to due to the missing virtual destructor) boost::any or wrap it and provide a templated conversion operator.
#include <boost/any.hpp>
#include <iostream>
struct converting_any {
converting_any(boost::any* a) : a(a) {}
template<typename T>
operator T() { return boost::any_cast<T>(*a); } // dereference to get the throwing version
private:
boost::any* a; // wrapped any
};
int main()
{
int i = 3; std::string j = "asddf";
boost::any a = i;
int i2 = converting_any(&a);
try {
std::string j2 = converting_any(&a);
} catch(...) {
std::cout << "Failure." << std::endl;
}
a = j;
std::string j3 = converting_any(&a);
return 0;
}
You could return a reference wrapper which postpones the cast until its needed:
struct converter {
converter(boost::any & any) : any(any) {}
template <typename T>
operator T() {return boost::any_cast<T>(any);}
boost::any & any;
};
converter get(tags key)
{
return map_[key];
}
The template argument can be deduced from the type being converted to, so your int example will work without an explicit template argument.
Note that, as with your version, this will fail if the template parameter doesn't match the variant's type, as demonstrated in your example when attempting to convert const char * to std::string.

C++ keeping a collection of pointers to template objects, all derived from a non-template class

I have a list of object "identifiers" (a long enumeration list, with a unique value per "identifier"):
enum Identifier {
Enum0, // an identifier for a bool value
Enum1, // ... for a float value
Enum2, // ... for an int value
// etc.
};
I wish to maintain a collection of Value objects associated with these identifiers. hese Value objects contain a single value, but this value may be integer, floating point, boolean or some other (simple) type. This is in the context of managing a set of configuration values in a system. Later on I plan to extend these value types to support validation of the internal value, and relate some values to other values.
However I wish to use templates for these Value classes, because I want to write operations on these Values generically. If I were to use inheritance I would have BaseValue, then derive IntValue, FloatValue, etc. from BaseValue. Instead I have Value, Value, etc.
But I also want to store an access mechanism to each of these Values in a single collection. I want one class to instantiate all of them and maintain them in the collection. If I were using inheritance, I could use a vector of pointers to BaseValue. But because I'm using templates, these classes are not polymorphically related to each other.
So I thought about making them based on an (empty?) abstract base class that is not parameterised:
class BaseParameter {
};
template<typename T>
class Parameter : public BaseParameter {
public:
explicit Parameter(T val) : val_(val) {}
void set(ParameterSource src) { val_ = extract<T>(src); }
T get() { return val_; };
private:
T val_;
};
Note that the 'set' member function takes a "ParameterSource", which is a source of a value that is 'reinterpreted' by specific "to_type" functions. It's an API function out of my control - I have to interpret the type myself, given that I know what the type is meant to be, set below. That's what extract does - it's specialised for various T types like float, int, bool.
Then I can add them to a std::vector like this:
std::vector<BaseParameter *> vec(10);
vec[Enum0] = new Parameter<bool>(true); // this is where I state that it's a 'bool'
vec[Enum1] = new Parameter<float>(0.5); // ... or a float ...
vec[Enum2] = new Parameter<int>(42); // ... or an int ...
I know I should probably use unique_ptr but for now I'm just trying to get this working. So far this seems to work fine. But I'm wary of it because I'm not sure the full type of the instantiated templates is going to be retained at run-time.
Later I want to index the 'vec' by an arbitrary enum value, retrieve the parameter and call a member function on it:
void set_via_source(Identifier id, ParameterSource source) {
// if id is in range...
vec[id]->set(source);
}
And other code that makes use of these configuration values (and therefore knows the type) can access them with:
int foo = vec[Enum2]->get() * 7;
This seemed to work, most of the time. It compiles. I've had some odd crashes I can't explain, that tend to crash the debugger too. But I'm very suspicious of it, because I don't know whether C++ is able to determine the real type of the pointed-to object (including the parameterised type), because the base class isn't parameterised itself.
Unfortunately it seems to me that if I parameterise the base class, then I essentially remove the commonality between these Value classes that allow them to be stored in a single container.
I took a look at boost::any to see if that might help, but I'm not sure it would apply in this case.
At a higher level, what I'm trying to do is connect a vast collection of configuration items from an external source (via an API) that delivers values of different type depending on the item, and store them locally so that the rest of my code can easily access them as if they are simple data members. I also want to avoid writing a giant switch statement (because that would work).
Is this something that Type Erasure might help me with?
If you know at compile time the type associated with each enum, you can do this "easily" with boost::variant and without type-erasure or even inheritance. (Edit: The first solution uses a lot of C++11 features. I put a less-automatic but C++03 conformant solution at the end.)
#include <string>
#include <vector>
#include <boost/variant.hpp>
#include <boost/variant/get.hpp>
// Here's how you define your enums, and what they represent:
enum class ParameterId {
is_elephant = 0,
caloric_intake,
legs,
name,
// ...
count_
};
template<ParameterId> struct ConfigTraits;
// Definition of type of each enum
template<> struct ConfigTraits<ParameterId::is_elephant> {
using type = bool;
};
template<> struct ConfigTraits<ParameterId::caloric_intake> {
using type = double;
};
template<> struct ConfigTraits<ParameterId::legs> {
using type = int;
};
template<> struct ConfigTraits<ParameterId::name> {
using type = std::string;
};
// ...
// Here's the stuff that makes it work.
class Parameters {
private:
// Quick and dirty uniquifier, just to show that it's possible
template<typename...T> struct TypeList {
using variant = boost::variant<T...>;
};
template<typename TL, typename T> struct TypeListHas;
template<typename Head, typename...Rest, typename T>
struct TypeListHas<TypeList<Head, Rest...>, T>
: TypeListHas<TypeList<Rest...>, T> {
};
template<typename Head, typename...Rest>
struct TypeListHas<TypeList<Head, Rest...>, Head> {
static const bool value = true;
};
template<typename T> struct TypeListHas<TypeList<>, T> {
static const bool value = false;
};
template<typename TL, typename T, bool B> struct TypeListMaybeAdd;
template<typename TL, typename T> struct TypeListMaybeAdd<TL, T, false> {
using type = TL;
};
template<typename...Ts, typename T>
struct TypeListMaybeAdd<TypeList<Ts...>, T, true> {
using type = TypeList<Ts..., T>;
};
template<typename TL, typename T> struct TypeListAdd
: TypeListMaybeAdd<TL, T, !TypeListHas<TL, T>::value> {
};
template<typename TL, int I> struct CollectTypes
: CollectTypes<typename TypeListAdd<TL,
typename ConfigTraits<ParameterId(I)>::type
>::type, I - 1> {
};
template<typename TL> struct CollectTypes<TL, 0> {
using type = typename TypeListAdd<TL,
typename ConfigTraits<ParameterId(0)>::type
>::type::variant;
};
public:
using value_type =
typename CollectTypes<TypeList<>, int(ParameterId::count_) - 1>::type;
template<ParameterId pid>
using param_type = typename ConfigTraits<pid>::type;
// It would be better to not initialize all the values twice, but this
// was easier.
Parameters() : values_(size_t(ParameterId::count_)) {
clear(std::integral_constant<int, int(ParameterId::count_) - 1>());
}
// getter for when you know the id at compile time. Should have better
// error checking.
template<ParameterId pid>
typename ConfigTraits<pid>::type get() {
// The following will segfault if the value has the wrong type.
return *boost::get<typename ConfigTraits<pid>::type>(&values_[int(pid)]);
}
// setter when you know the id at compile time
template<ParameterId pid>
void set(typename ConfigTraits<pid>::type new_val) {
values_[int(pid)] = new_val;
}
// getter for an id known only at runtime; returns a boost::variant;
value_type get(ParameterId pid) {
return values_[int(pid)];
}
private:
// Initialize parameters to default values of the correct type
template<int I> void clear(std::integral_constant<int, I>) {
values_[I] = param_type<ParameterId(I)>();
clear(std::integral_constant<int, I - 1>());
}
void clear(std::integral_constant<int, 0>) {
values_[0] = param_type<ParameterId(0)>();
}
std::vector<value_type> values_;
};
// And finally, a little test
#include <iostream>
int main() {
Parameters parms;
std::cout << ('(' + parms.get<ParameterId::name>() + ')')<< ' '
<< parms.get<ParameterId::is_elephant>() << ' '
<< parms.get<ParameterId::caloric_intake>() << ' '
<< parms.get<ParameterId::legs>() << std::endl;
parms.set<ParameterId::is_elephant>(true);
parms.set<ParameterId::caloric_intake>(27183.25);
parms.set<ParameterId::legs>(4);
parms.set<ParameterId::name>("jumbo");
std::cout << ('(' + parms.get<ParameterId::name>() + ')')<< ' '
<< parms.get<ParameterId::is_elephant>() << ' '
<< parms.get<ParameterId::caloric_intake>() << ' '
<< parms.get<ParameterId::legs>() << std::endl;
return 0;
}
For the benefit of those who can't yet use C++11, here's a version which uses non-class enums and which is not smart enough to build the boost::variant type by itself, so you have to provide it manually:
#include <string>
#include <vector>
#include <boost/variant.hpp>
#include <boost/variant/get.hpp>
// Here's how you define your enums, and what they represent:
struct ParameterId {
enum Id {
is_elephant = 0,
caloric_intake,
legs,
name,
// ...
count_
};
};
template<int> struct ConfigTraits;
// Definition of type of each enum
template<> struct ConfigTraits<ParameterId::is_elephant> {
typedef bool type;
};
template<> struct ConfigTraits<ParameterId::caloric_intake> {
typedef double type;
};
template<> struct ConfigTraits<ParameterId::legs> {
typedef int type;
};
template<> struct ConfigTraits<ParameterId::name> {
typedef std::string type;
};
// ...
// Here's the stuff that makes it work.
// C++03 doesn't have integral_constant, so we need to roll our own:
template<int I> struct IntegralConstant { static const int value = I; };
template<typename VARIANT>
class Parameters {
public:
typedef VARIANT value_type;
// It would be better to not initialize all the values twice, but this
// was easier.
Parameters() : values_(size_t(ParameterId::count_)) {
clear(IntegralConstant<int(ParameterId::count_) - 1>());
}
// getter for when you know the id at compile time. Should have better
// error checking.
template<ParameterId::Id pid>
typename ConfigTraits<pid>::type get() {
// The following will segfault if the value has the wrong type.
return *boost::get<typename ConfigTraits<pid>::type>(&values_[int(pid)]);
}
// setter when you know the id at compile time
template<ParameterId::Id pid>
void set(typename ConfigTraits<pid>::type new_val) {
values_[int(pid)] = new_val;
}
// getter for an id known only at runtime; returns a boost::variant;
value_type get(ParameterId::Id pid) {
return values_[int(pid)];
}
private:
// Initialize parameters to default values of the correct type
template<int I> void clear(IntegralConstant<I>) {
values_[I] = typename ConfigTraits<I>::type();
clear(IntegralConstant<I - 1>());
}
void clear(IntegralConstant<0>) {
values_[0] = typename ConfigTraits<0>::type();
}
std::vector<value_type> values_;
};
// And finally, a little test
#include <iostream>
int main() {
Parameters<boost::variant<bool, int, double, std::string> > parms;
std::cout << ('(' + parms.get<ParameterId::name>() + ')')<< ' '
<< parms.get<ParameterId::is_elephant>() << ' '
<< parms.get<ParameterId::caloric_intake>() << ' '
<< parms.get<ParameterId::legs>() << std::endl;
parms.set<ParameterId::is_elephant>(true);
parms.set<ParameterId::caloric_intake>(27183.25);
parms.set<ParameterId::legs>(4);
parms.set<ParameterId::name>("jumbo");
std::cout << ('(' + parms.get<ParameterId::name>() + ')')<< ' '
<< parms.get<ParameterId::is_elephant>() << ' '
<< parms.get<ParameterId::caloric_intake>() << ' '
<< parms.get<ParameterId::legs>() << std::endl;
return 0;
}

C++11 Tagged Tuple

C++11 tuples are nice, but they have two huge disadvantages to me, accessing members by index is
unreadable
difficult to maintain (if I add an element in the middle of the tuple, I'm screwed)
In essence what I want to achieve is this
tagged_tuple <name, std::string, age, int, email, std::string> get_record (); {/*...*/}
// And then soomewhere else
std::cout << "Age: " << get_record().get <age> () << std::endl;
Something similar (type tagging) is implemented in boost::property_map, but I ca'nt get my head around how to implement it in a tuple with arbitary number of elements
PS
Please do not suggest defining an enum with tuple element indices.
UPD
OK, here is a motivation. In my projects I need to be able to define lots of different tuples 'on-the-fly' and all of them need to have certain common functions and operators. This is not possible to achieve with structs
UPD2
Actually my example is probably a bit unrealistic to implement. How about this?
tagged_tuple <tag<name, std::string>, tag<age, int>, tag<email, std::string>> get_record (); {/*...*/}
// And then somewhere else
std::cout << "Age: " << get_record().get <age> () << std::endl;
I'm not aware of any existing class that does this, but it's fairly easy to throw something together using a std::tuple and an indexing typelist:
#include <tuple>
#include <iostream>
template<typename... Ts> struct typelist {
template<typename T> using prepend = typelist<T, Ts...>;
};
template<typename T, typename... Ts> struct index;
template<typename T, typename... Ts> struct index<T, T, Ts...>:
std::integral_constant<int, 0> {};
template<typename T, typename U, typename... Ts> struct index<T, U, Ts...>:
std::integral_constant<int, index<T, Ts...>::value + 1> {};
template<int n, typename... Ts> struct nth_impl;
template<typename T, typename... Ts> struct nth_impl<0, T, Ts...> {
using type = T; };
template<int n, typename T, typename... Ts> struct nth_impl<n, T, Ts...> {
using type = typename nth_impl<n - 1, Ts...>::type; };
template<int n, typename... Ts> using nth = typename nth_impl<n, Ts...>::type;
template<int n, int m, typename... Ts> struct extract_impl;
template<int n, int m, typename T, typename... Ts>
struct extract_impl<n, m, T, Ts...>: extract_impl<n, m - 1, Ts...> {};
template<int n, typename T, typename... Ts>
struct extract_impl<n, 0, T, Ts...> { using types = typename
extract_impl<n, n - 1, Ts...>::types::template prepend<T>; };
template<int n, int m> struct extract_impl<n, m> {
using types = typelist<>; };
template<int n, int m, typename... Ts> using extract = typename
extract_impl<n, m, Ts...>::types;
template<typename S, typename T> struct tt_impl;
template<typename... Ss, typename... Ts>
struct tt_impl<typelist<Ss...>, typelist<Ts...>>:
public std::tuple<Ts...> {
template<typename... Args> tt_impl(Args &&...args):
std::tuple<Ts...>(std::forward<Args>(args)...) {}
template<typename S> nth<index<S, Ss...>::value, Ts...> get() {
return std::get<index<S, Ss...>::value>(*this); }
};
template<typename... Ts> struct tagged_tuple:
tt_impl<extract<2, 0, Ts...>, extract<2, 1, Ts...>> {
template<typename... Args> tagged_tuple(Args &&...args):
tt_impl<extract<2, 0, Ts...>, extract<2, 1, Ts...>>(
std::forward<Args>(args)...) {}
};
struct name {};
struct age {};
struct email {};
tagged_tuple<name, std::string, age, int, email, std::string> get_record() {
return { "Bob", 32, "bob#bob.bob"};
}
int main() {
std::cout << "Age: " << get_record().get<age>() << std::endl;
}
You'll probably want to write const and rvalue get accessors on top of the existing one.
C++ does not have a struct type that can be iteratable like a tuple; it's either/or.
The closest you can get to that is through Boost.Fusion's struct adapter. This allows you to use a struct as a Fusion sequence. Of course, this also uses a series of macros, and it requires you to list the struct's members explicitly in the order you want to iterate over them. In the header (assuming you want to iterate over the struct in many translation units).
Actually my example is probably a bit unrealistic to implement. How about this?
You could implement something like that, but those identifiers need to actually be types or variables or something.
I have my own implementation to show off, wich can allow you not to declare the attributes on top of the file. A version with declared attributes exists too, but there is no need to define them, declaration is sufficient.
It is pure STL, of course, and do not use the preprocessor.
Example:
#include <named_tuples/tuple.hpp>
#include <string>
#include <iostream>
#include <vector>
namespace {
unsigned constexpr operator "" _h(const char* c,size_t) { return named_tuples::const_hash(c); }
template <unsigned Id> using at = named_tuples::attribute_init_int_placeholder<Id>;
using named_tuples::make_tuple;
}
int main() {
auto test = make_tuple(
at<"nom"_h>() = std::string("Roger")
, at<"age"_h>() = 47
, at<"taille"_h>() = 1.92
, at<"liste"_h>() = std::vector<int>({1,2,3})
);
std::cout
<< test.at<"nom"_h>() << "\n"
<< test.at<"age"_h>() << "\n"
<< test.at<"taille"_h>() << "\n"
<< test.at<"liste"_h>().size() << std::endl;
test.at<"nom"_h>() = "Marcel";
++test.get<1>();
std::cout
<< test.get<0>() << "\n"
<< test.get<1>() << "\n"
<< test.get<2>() << "\n"
<< test.get<3>().size() << std::endl;
return 0;
}
Find the complete source here https://github.com/duckie/named_tuple. Feel free to read, it is quite simple.
The real problems you have to solve here are:
Are the tags mandatory or optional?
Are the tags unique? Is it enforced at compile time?
In which scope does the tag reside? Your example seems to declare the tags inside the declaring scope instead of encapsulated in the type, which might not be optimal.
ecatmur proposed a good solution; but the tags are not encapsulated and the tag declaration is somehow clumsy. C++14 will introduce tuple addressing by type, which will simplify his design and guarantee uniqueness of the tags, but not solve their scope.
Boost Fusion Map can also be used for something similar, but again, declaring the tags is not ideal.
There is a proposal for something similar on the c++ Standard Proposal forum, which would simplify the syntax by associating a name to the template parameter directly.
This link lists different ways of implementing this (including ecatmur's solution) and presents a different use-case for this syntax.
Here's another way to do it, it's a bit uglier to define the types but it helps prevent errors at compile time because you define the pairs with a type_pair class (much like std::map). Adding a check to make sure your keys/name are unique at compile time is the next step
Usage:
using user_t = tagged_tuple<type_pair<struct name, std::string>, type_pair<struct age, int>>;
// it's initialized the same way as a tuple created with the value types of the type pairs (so tuple<string, int> in this case)
user_t user { "chris", 21 };
std::cout << "Name: " << get<name>(user) << std::endl;
std::cout << "Age: " << get<age>(user) << std::endl;
// you can still access properties via numeric indexes as if the class was defined as tuple<string, int>
std::cout << "user[0] = " << get<0>(user) << std::endl;
I opted against having get be a member function to keep it as similar to std::tuple as possible but you could easily add one to the class.
Source code here
Here is an implementation similar to ecatmur's answer using the brigand metaprogramming library (https://github.com/edouarda/brigand):
#include <iostream>
#include <brigand/brigand.hpp>
template<typename Members>
class TaggedTuple{
template<typename Type>
struct createMember{
using type = typename Type::second_type;
};
using DataTuple = brigand::transform<Members, createMember<brigand::_1>>;
using Keys = brigand::keys_as_sequence<Members, brigand::list>;
brigand::as_tuple<DataTuple> members;
public:
template<typename TagType>
auto& get(){
using index = brigand::index_of<Keys, TagType>;
return std::get<index::value>(members);
}
};
int main(){
struct FloatTag{};
struct IntTag{};
struct DoubleTag{};
TaggedTuple<brigand::map<
brigand::pair<FloatTag, float>,
brigand::pair<IntTag, int>,
brigand::pair<DoubleTag, double>>> tagged;
tagged.get<DoubleTag>() = 200;
auto val = tagged.get<DoubleTag>();
std::cout << val << std::endl;
return 0;
}
I implemented "c++ named tuple" using boost preprocessor. Please see the Sample usage below. By deriving from tuple, I get comparison, printing, hash, serialization for free (assuming they are defined for tuple).
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/comma_if.hpp>
#define CM_NAMED_TUPLE_ELEMS_ITR(r, xxx, index, x ) BOOST_PP_COMMA_IF(index) BOOST_PP_TUPLE_ELEM(2,0,x)
#define CM_NAMED_TUPLE_ELEMS(seq) BOOST_PP_SEQ_FOR_EACH_I(CM_NAMED_TUPLE_ELEMS_ITR, "dum", seq)
#define CM_NAMED_TUPLE_PROPS_ITR(r, xxx, index, x) \
BOOST_PP_TUPLE_ELEM(2,0,x) BOOST_PP_CAT(get_, BOOST_PP_TUPLE_ELEM(2,1,x))() const { return get<index>(*this); } \
void BOOST_PP_CAT(set_, BOOST_PP_TUPLE_ELEM(2,1,x))(const BOOST_PP_TUPLE_ELEM(2,0,x)& oo) { get<index>(*this) = oo; }
#define CM_NAMED_TUPLE_PROPS(seq) BOOST_PP_SEQ_FOR_EACH_I(CM_NAMED_TUPLE_PROPS_ITR, "dum", seq)
#define cm_named_tuple(Cls, seq) struct Cls : tuple< CM_NAMED_TUPLE_ELEMS(seq)> { \
typedef tuple<CM_NAMED_TUPLE_ELEMS(seq)> Base; \
Cls() {} \
template<class...Args> Cls(Args && ... args) : Base(args...) {} \
struct hash : std::hash<CM_NAMED_TUPLE_ELEMS(seq)> {}; \
CM_NAMED_TUPLE_PROPS(seq) \
template<class Archive> void serialize(Archive & ar, arg const unsigned int version)() { \
ar & boost::serialization::base_object<Base>(*this); \
} \
}
//
// Example:
//
// class Sample {
// public:
// void do_tata() {
// for (auto& dd : bar2_) {
// cout << dd.get_from() << " " << dd.get_to() << dd.get_tata() << "\n";
// dd.set_tata(dd.get_tata() * 5);
// }
// cout << bar1_ << bar2_ << "\n";
// }
//
// cm_named_tuple(Foo, ((int, from))((int, to))((double, tata))); // Foo == tuple<int,int,double> with named get/set functions
//
// unordered_set<Foo, Foo::hash> bar1_;
// vector<Foo> bar2_;
// };
Please note that code sample above assumes you have defined "generic" ostream printing functions for vector/tuple/unordered_set.
I have "solved" a similar problem in production code. First, I have an ordinary struct (actually a class with various member functions, but it's only the data members which we are interested in here)...
class Record
{
std::string name;
int age;
std::string email;
MYLIB_ENABLE_TUPLE(Record) // macro
};
Then just below the struct definition, but outside of any namespace, I have another macro:
MYLIB_DECLARE_TUPLE(Record, (o.name, o.age, o.email))
The disadvantage with this approach is that the member names must be listed twice, but this is the best I have been able to come up with while still permitting traditional member access syntax within the struct's own member functions. The macro appears very near the definitions of the data members themselves, so it is not too hard to keep them in sync with each other.
In another header file I have a class template:
template <class T>
class TupleConverter;
The first macro is defined so as to declare this template to be a friend of the struct, so it can access its private data members:
#define MYLIB_ENABLE_TUPLE(TYPE) friend class TupleConverter<TYPE>;
The second macro is defined so as to introduce a specialization of the template:
#define MYLIB_DECLARE_TUPLE(TYPE, MEMBERS) \
template <> \
class TupleConverter<TYPE> \
{ \
friend class TYPE; \
static auto toTuple(TYPE& o) \
-> decltype(std::tie MEMBERS) \
{ \
return std::tie MEMBERS; \
} \
public: \
static auto toTuple(TYPE const& o) \
-> decltype(std::tie MEMBERS) \
{ \
return std::tie MEMBERS; \
} \
};
This creates two overloads of the same member function name, TupleConverter<Record>::toTuple(Record const&) which is public, and TupleConverter<Record>::toTuple(Record&) which is private and accessible only to Record itself through friendship. Both return their argument converted to a tuple of references to private data members by way of std::tie. The public const overload returns a tuple of references to const, the private non-const overload returns a tuple of references to non-const.
After preprocessor substitution, both friend declarations refer to entities defined in the same header file, so there should be no chance of other code abusing the friendship to break encapsulation.
toTuple can't be a member function of Record, because its return type can't be deduced until the definition of Record is complete.
Typical usage looks like this:
// lexicographical comparison
bool operator< (Record const& a, Record const& b)
{
return TupleConverter<Record>::toTuple(a) < TupleConverter<Record>::toTuple(b);
}
// serialization
std::ostream& operator<< (std::ostream& os, Record const& r)
{
// requires template<class... Ts> ostream& operator<<(ostream&, tuple<Ts...>) defined elsewhere
return os << TupleConverter<Record>::toTuple(r);
}
There are many ways this could be extended, for example by adding another member function in TupleConverter which returns a std::vector<std::string> of the names of the data members.
If I'd been allowed to use variadic macros then the solution might have been even better.