How to construct a wrapper tuple from implementer tuple? - c++

I have some implementer classes (impls) and some wrappers for user, implemented in C++. I want to hold impls and wrappers in two different tuples so that i can initialize my impls by a single allocation. (I have other reasons too:).
The thing is tuple class of visual studio 2012 standard library does not allow me to construct my wrapper tuple without a const referenced copy constructor of wrappers. sadly I need to const_cast in that case, such as:
#include <iostream>
#include <type_traits>
#include <tuple>
#include <typeinfo>
template <typename Member>
struct A
{
A(Member& m) : member(m)
{ std::cout << typeid(Member).name() << " MMBR " << member << std::endl; }
A(const Member& m) : member(const_cast<Member&>(m))
{ std::cout << typeid(Member).name() << " CMBR " << member << std::endl; }
void Print()
{
std::cout << typeid(Member).name() << " PRNT " << member << std::endl;
}
Member& member;//yes I need to hold this as a mutable reference
};
int main()
{
typedef std::tuple<A<int>, A<double>, A<short>> WrapperTuple;
typedef std::tuple<int, double, short> Tuple;
Tuple t(0, 1, 2);
WrapperTuple w(t);
std::get<1>(w).Print();
return std::cin.get();
}
The code above compiles and runs as intended, but if I delete/comment out the const-ref-ctor of wrapper class A neither my VS2012 compiler nor my gcc4.7.2 compiler compiles the code. (1) What am I doing wrong?
Since I don't have a good documentation for c++11, I guess that variadic copy ctor of tuple only takes a const ref of other tuple. If so, (2) why doesn't tuple class have such ctor? I mean the main reason behind.
To sum up I want to hold all impls and wrappers together in a tuple so I can allocate with a single action (i.e. make_shared). Tuple is somewhat a must because I have written some helpers so that I can lookup by type in compile time (e.g. Get<A<int>>(w)) (3) Is there a neat way to hold a reference to the impl such that I would not need to allocate each impl separately.

The copy constructor of std::tuple, even the converting one, obviously copies all the elements, and since a copy shouldn't change the copied-from element, they're marked as const. This behaviour is perfectly reasonable, most of the time.
The workaround for your special case is a bit more involved that what you may like, but it works. The basic idea is that you, conceptually, don't want to copy the tuple, but you want to use it's elements as an initializer to the elements of your other tuple, as such their constness should be preserved.
template<unsigned...> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};
namespace aux{
template<class... Ts, unsigned... Is>
std::tuple<Ts&...> tie_all_(std::tuple<Ts...>& other, seq<Is...>){
return std::tie(std::get<Is>(other)...);
}
} // aux::
template<class... Ts>
std::tuple<Ts&...> tie_all(std::tuple<Ts...>& other){
return aux::tie_all_(other, gen_seq<sizeof...(Ts)>());
}
The code is used like this: WrapperTuple w(tie_all(t));. Now you can get rid of the Member const& constructor.
You could even go further and write a function that turns a tuple into a wrapper tuple, thus getting rid of having to specify the type manually:
template<class... Ts>
std::tuple<A<Ts>...> wrap_all(std::tuple<Ts...>& other){
return tie_all(other);
}
// ...
auto w(wrap_all(t));
And if you have different wrapper classes:
template<template<class> class Wrapper, class... Ts>
std::tuple<Wrapper<Ts>...> wrap_all_in(std::tuple<Ts...>& other){
return tie_all(other);
}
// ...
auto w = wrap_all_in<A>(t);

Why don't you just create wrapped_tuple template that wraps the whole tuple and provides an implementation of get? It seems redundant to hold references to individual tuple elements, since the tuple has a fixed layout and the compiler can emit trivial code to reference an individual element given a reference to the tuple.
For example (and doing this without variadic templates, which is a bit annoying):
template<typename Tuple> class wrapped_tuple;
template<size_t I, typename Tuple>
typename std::tuple_element<I, Tuple>::type&
Get(wrapped_tuple<Tuple>& w) {
return std::get<I>(w.tuple_);
}
template<typename Tuple> class wrapped_tuple {
template<size_t I, typename Uple>
friend typename std::tuple_element<I, Uple>::type&
::Get(wrapped_tuple<Uple>& w);
public:
wrapped_tuple(Tuple& t) : tuple_(t) {}
private:
Tuple& tuple_;
};
template<typename Tuple>
wrapped_tuple<Tuple> wrap_tuple(Tuple& tup) {
return wrapped_tuple<Tuple>(tup);
}
Here on ideone.

Related

How to save variable number of arguments using variadic template arguments?

I would like to create template class which could store function pointer and arguments for a this function so the function can be later invoked with this arguments.
I would like to write this universally and not to depend on argument types or number.
Here is a scatch of the idea with the use of variadic templates of c++11:
template<class T, typename... Params>
class LazyEvaluation {
private:
// Function to be invoked later
T (*f)(Params...);
// Params for function f
Params... storedParams; // This line is not compilable!
bool evaluated;
T result;
public:
// Constructor remembers function pointer and parameters
LazyEvaluation(T (*f)(Params...),Params... params)
: f(f),
storedParams(params) //this line also cannot be compiled
{}
// Method which can be called later to evaluate stored function with stored arguments
operator T&() {
// if not evaluated then evaluate
if (! evaluated) {
result = f(storedParams...);
evaluated = true;
}
return result;
}
}
I would like to have at least the public interface of this class type safe if it is possible. Although getting this work at least somehow is more important.
I've managed to save the variable number of arguments somehow. But I wasn't able to pass them to the function f. I will write it to answers, but I would like you to think about your own solutions before you see my ugly not working attempt.
I am tring to compile the code above with Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012), but it would be best if a compiler independent solution would exist.
Thank you
Here is how I tried to solve it:
The parametr pack can be recursivle expanded and each parametr saved. Function store is supposed to do it. It uses one (two times overloaded) helper function.
template<typename T>
void storeHelperFunction(void*& memory, T last) {
*((T*)memory) = last;
memory = (void*)((char*)memory + sizeof(T));
}
template<typename T, typename... Params>
void storeHelperFunction(void*& memory, T first, Params... rest) {
storeHelperFunction(memory, first);
storeHelperFunction(memory, rest...);
}
template<typename... Params>
void store(void* memory, Params... args) {
// Copy of pointer to memory was done when passing it to this function
storeHelperFunction(memory, args...);
}
Function store takes a pointer to memory where the varialbe number of arguments is supposed to be saved.
The pointer can point to some dynamicly allocated memory or beter to the structure which size is equal to sizeof...(Params).
Such structure which has exactly any desiared size can be constructed using template metaprogramming:
template <int N>
struct allocatorStruct {
char byte1;
allocatorStruct<N-1> next;
};
template <>
struct allocatorStruct<1> {};
I am not sure what the standart says or how the other compilers than the microsoft one compile it. But using my compiler the sizeof(allocatorStruct) is equal to N for any N which is greater or equal to 1.
Hence allocatorStruct<sizeof...(Params)> has the same size as Params.
Another way to create something which has the same size as Params is to use a type char [sizeof...(Params)]. This has the disadvantage that the compiler passes only pointer to this array when you try to pass such array as argument.
That is why it is better to use allocatorStruct<sizeof...(Params)>.
And now the main idea:
When saving the function we can cast it to: T (*)(allocatorStruct<sizeof...(Params)>).
When saving the arguments for the function we can save them to struct of the type allocatorStruct<sizeof...(Params)>.
The size of the arguments is the same. Although the function pointer lies about the type of the function the function pointed to will get its data correctly.
At least I hoped. Depending on the calling convention I expected that the passed arguments can be reordered or wrong because of the difference between left to right saving arguments and right to left passing. But it wasn't the case. Using __cdecl calling convention only first argument was passed and the other was lost. With other calling conventions the program stoped working.
I didn't spend much time debugging it and looking to data in memory(on stack). Is it at least right way to go?
Simply use a lambda expression
// Some function.
int add(int a, int b) {
return a + b;
}
auto lazyFunc = [] { return add(1, 2); };
std::cout << lazyFunc() << std::endl; // Evaluate function and output result.
If you really want to create a class that only evaluates the function once (lazily), using variadic templates, you could do something like in the following code.
I also made the class as such that you don't have to create a new instance every time the parameters change. I use a std::tuple to store the given arguments, and compare against previously given arguments. If the arguments differ, then the function will be reevaluated.
Functions are passed around and stored using a std::function wrapper so I don't have to work with raw function pointers (yuck).
#include <iostream>
#include <functional>
#include <utility>
#include <tuple>
template <typename T>
class LazyEvaluation {};
template <typename ReturnType, typename... Params>
class LazyEvaluation<ReturnType(Params...)> {
private:
std::function<ReturnType(Params...)> func_;
ReturnType result;
std::tuple<Params...> oldParams; // Contains the previous arguments.
public:
explicit LazyEvaluation(std::function<ReturnType(Params...)> func)
: func_(std::move(func)) {}
template <typename... Args>
ReturnType operator() (Args&&... args) {
auto newParams = std::make_tuple(std::forward<Args>(args)...);
// Check if new arguments.
if (newParams != oldParams) {
result = func_(std::forward<Args>(args)...);
oldParams = newParams;
std::cout << "Function evaluated" << std::endl;
}
std::cout << "Returned result" << std::endl;
return result;
}
};
int main() {
auto f = [] (int a, int b) {
return a + b;
};
// Specify function type as template parameter.
// E.g. ReturnType(Param1Type, Param2Type, ..., ParamNType)
LazyEvaluation<int(int, int)> ld(f);
std::cout << ld(1, 2) << std::endl;
std::cout << ld(1, 2) << std::endl;
std::cout << ld(3, 4) << std::endl;
}
Output:
Function evaluated
Returned result
3
Returned result
3
Function evaluated
Returned result
7
Given the standard machinery for forming variadic index packs:
template <std::size_t... I> struct index_sequence {};
template <std::size_t N, std::size_t... I>
struct make_index_sequence : public make_index_sequence<N-1, N-1, I...> {};
template <std::size_t... I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
and to call functions with unpacked tuple arguments:
template <typename Function, typename... Types, std::size_t... I>
auto apply_(Function&& f, const std::tuple<Types...>& t, index_sequence<I...>)
-> decltype(std::forward<Function>(f)(std::get<I>(t)...)) {
return std::forward<Function>(f)(std::get<I>(t)...);
}
template <typename Function, typename... Types>
auto apply(Function&& f, const std::tuple<Types...>& t)
-> decltype(apply_(f, t, make_index_sequence<sizeof...(Types)>())) {
return apply_(f, t, make_index_sequence<sizeof...(Types)>());
}
This is fairly straightforward:
template<typename Function, typename... Params>
class LazyEvaluation {
private:
typedef decltype(std::declval<Function>()(std::declval<Params>()...)) result_type;
// Function to be invoked later
Function f;
// Params for function f
std::tuple<Params...> storedParams;
mutable bool evaluated;
union {
std::aligned_storage<sizeof(result_type)> space;
mutable result_type result;
};
// Method which can be called later to evaluate stored function with stored arguments
void evaluate() const {
// if not evaluated then evaluate
if (! evaluated) {
new (&result) result_type{apply(f, storedParams)};
evaluated = true;
}
}
public:
// Constructor remembers function pointer and parameters
LazyEvaluation(Function f, Params... params)
: f(std::move(f)),
storedParams(std::move(params)...),
evaluated(false)
{}
~LazyEvaluation() {
if (evaluated)
result.~result_type();
}
operator result_type&() {
evaluate();
return result;
}
operator const result_type& () const {
evaluate();
return result;
}
};
template <typename Function, typename... Params>
LazyEvaluation<Function, Params...>
make_lazy(Function&& f, Params&&... params) {
return {std::forward<Function>(f), std::forward<Params>(params)...};
}
I've used a union and placement new to store the result of evaluation so that it doesn't need to be a default-constructible type, and some mutable tricks so that a const LazyEvaluator can be converted as well as a non-const instance.

Create functors from functions with unknown argument count

I wrote a program in C++ & boost. Is it possible to write a template class producing functors from functions with an unknown number of arguments, e.g. my_call<func>(vector<variant>), where fun can be bool fun(string) or bool fun(int, int, string), etc.?
First, it is important to recognize that boost::variant<> is a class template that requires the list of all the possible types it can hold. So, you won't have just a vector<variant>, but rather a vector<variant<string, double>>, or vector<variant<int, double, string, my_class>>, and you won't be able to mix them.
This made me think you might want to use boost::any rather than boost::variant<>. Thus, I present here a solution that works with boost::variant and can be slightly modified to use boost::any, so you can pick the version you prefer.
To begin with, I must admit that the solution is simple to use but not so simple to understand, so I will have to introduce some machinery first. This machinery is common to both the variant-based and the any-based solution.
//=============================================================================
// META-FUNCTIONS FOR CREATING INDEX LISTS
// The structure that encapsulates index lists
template <size_t... Is>
struct index_list
{
};
// Collects internal details for generating index ranges [MIN, MAX)
namespace detail
{
// Declare primary template for index range builder
template <size_t MIN, size_t N, size_t... Is>
struct range_builder;
// Base step
template <size_t MIN, size_t... Is>
struct range_builder<MIN, MIN, Is...>
{
typedef index_list<Is...> type;
};
// Induction step
template <size_t MIN, size_t N, size_t... Is>
struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
{
};
}
// Meta-function that returns a [MIN, MAX) index range
template<size_t MIN, size_t MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;
The meta-class index_range allows defining compile-time sequences of integers. An interesting proposal have been made by Jonathan Wakely to standardize this kind of construct, so that this whole machinery would not be needed. For the moment, however, we have to hand code this as done above.
Now that we can build compile-time integer sequences, we can exploit variadic templates and argument unpacking to create a dispatching mechanism that translates a vector of variant arguments into a regular argument list. Notice how the concrete variant<> type must be provided as a template argument. This will not be needed for the solution based on any.
// Headers needed for the implementation of the dispatcher
#include <vector>
#include <functional>
#include <boost/variant.hpp>
// Just for convenience
using namespace std;
using boost::variant;
//============================================================================
// DISPATCHER IMPLEMENTATION
// Call dispatching mechanism: notice how the underlying variant type
// must be provided as a template argument (the first one)
template<typename VT, typename R, typename... Args>
struct dispatcher
{
template<typename F>
dispatcher(F f) : _f(f) { }
// The call operator which performs the variant dispatch
R operator () (vector<VT> const& v)
{
if (v.size() != sizeof...(Args))
{
// Wrong number of arguments provided!
return false;
}
// Delegates to internal function call: needed for deducing
// a sequence of integers to be used for unpacking.
index_range<0, sizeof...(Args)> indexes;
return do_call(v, indexes);
}
private:
// The heart of the dispatching mechanism
template<size_t... Is>
R do_call(vector<VT> const& v, index_list<Is...> indexes)
{
return _f((get_ith<Args>(v, Is))...);
}
// Helper function that extracts a typed value from the variant.
template<typename T>
T get_ith(vector<VT> const& v, size_t i)
{
return boost::get<T>(v[i]);
}
// Wrapper that holds the function to be invoked.
function<R(Args...)> _f;
};
// Helper function that allows deducing the input function signature
template<typename VT, typename R, typename... Args>
function<R (vector<VT> const&)> get_dispatcher(R (*f)(Args...))
{
dispatcher<VT, R, Args...> d(f);
return d;
}
Finally, a short demonstration of how you could use this. Suppose we have two test functions such as the ones below:
#include <iostream>
bool test1(string s, double d)
{
cout << s << " " << d << endl;
return true;
}
bool test2(int i1, int i2, string s1, string s2)
{
cout << i1 << " " << i2 << " " << s1 << " " << s2 << endl;
return true;
}
What we want is to invoke them by building a vector of variants and have it dispatched to the desired function. Once again, I must stress the fact that we need to specify the list of all the types our variant can hold. Here, I will assume these types are string, double, and int, but your program might work with different ones.
Also, the solution is based on std::function<> for realizing the type erasure that allows you creating functors of different types and yet invoke them uniformly. Thus, a convenience type definition for this std::function<> (which in turn depends on the variant<> type we use) is provided as well:
int main()
{
// A helper type definition for the variant
typedef variant<int, double, string> vt;
// A helper type definition for the function wrapper
typedef function<bool (vector<vt>)> dispatcher_type;
// Get a caller for the first function
dispatcher_type f1 = get_dispatcher<vt>(test1);
// Prepare arguments for the first function
vector<vt> v = {"hello", 3.14};
// Invoke the first function
f1(v);
// Get a caller for the second function
dispatcher_type f2 = get_dispatcher<vt>(test2);
// Prepare arguments for the second function
v.assign({1, 42, "hello", "world"});
// Invoke the second function
f2(v);
}
Since all dispatchers have type dispatcher_type, you can easily put them into a container. However, you must be aware of the fact that attempts to invoke a function with the wrong number of arguments will be detected only at run-time (it is impossible to know at compile-time how many elements an std::vector<> contains). Thus, proper care must be taken.
As promised, I will now slightly modify this solution to use boost::any rather than boost::variant. The advantage is that since boost::any can hold any value, it is not necessary to specify the list of the possible types which can be used as function arguments.
While the helper machinery is unchanged, the core dispatcher class template must be modified as follows:
#include <vector>
#include <functional>
#include <boost/any.hpp>
using namespace std;
using boost::any;
//=============================================================================
// DISPATCHER IMPLEMENTATION
template<typename R, typename... Args>
struct dispatcher
{
template<typename F>
dispatcher(F f) : _f(f) { }
// The call operator which performs the dispatch
R operator () (vector<any> const& v)
{
if (v.size() != sizeof...(Args))
{
// Wrong number of arguments provided!
return false;
}
// Delegates to internal function call: needed for deducing
// a sequence of integers to be used for unpacking.
index_range<0, sizeof...(Args)> indexes;
return do_call(v, indexes);
}
private:
// The heart of the dispatching mechanism
template<size_t... Is>
R do_call(vector<any> const& v, index_list<Is...> indexes)
{
return _f((get_ith<Args>(v, Is))...);
}
// Helper function that extracts a typed value from the variant.
template<typename T>
T get_ith(vector<any> const& v, size_t i)
{
return boost::any_cast<T>(v[i]);
}
// Wrapper that holds the function to be invoked.
function<R(Args...)> _f;
};
// Helper function
template<typename R, typename... Args>
function<R (vector<any> const&)> get_dispatcher(R (*f)(Args...))
{
dispatcher<R, Args...> d(f);
return d;
}
As you see, the VT template argument has vanished. In particular, it is possible to call get_dispatcher without explicitly specifying any template argument. Using the same test functions we have defined for the variant-based solution, here is how you would adapt the main() routine:
int main()
{
// Helper type definition
typedef function<bool (vector<any>)> dispatcher_type;
// Get a caller for the first function
dispatcher_type f1 = get_dispatcher(test1);
// Get a caller for the second function
dispatcher_type f2 = get_dispatcher(test2);
// Prepare arguments for the first function
vector<any> v = {string("hello"), 3.14};
// Invoke the first function
f1(v);
// Prepare arguments for the second function
v.assign({1, 42, string("hello"), string("world")});
// Invoke the second function
f2(v);
}
The only disadvantage is that with boost::any you cannot assign string literals explicitly, because string literals are of type char [], and arrays cannot be used to initialize objects of type any:
any a = "hello"; // ERROR!
Thus, you have to either wrap them into string objects, or explicitly convert them to a pointer to char const*:
any a = string("hello"); // OK
any b = (char const*)"hello"; // OK
If this is not a huge problem for you, it's probably better to go for this second solution.

how to avoid undefined execution order for the constructors when using std::make_tuple

How can I use std::make_tuple if the execution order of the constructors is important?
For example I guess the execution order of the constructor of class A and the constructor of class B is undefined for:
std::tuple<A, B> t(std::make_tuple(A(std::cin), B(std::cin)));
I came to that conclusion after reading a comment to the question
Translating a std::tuple into a template parameter pack
that says that this
template<typename... args>
std::tuple<args...> parse(std::istream &stream) {
return std::make_tuple(args(stream)...);
}
implementation has an undefined execution order of the constructors.
Update, providing some context:
To give some more background to what I am trying to do, here is a sketch:
I want to read in some serialized objects from stdin with the help of CodeSynthesis XSD binary parsing/serializing. Here is an example of how such parsing and serialization is done: example/cxx/tree/binary/xdr/driver.cxx
xml_schema::istream<XDR> ixdr (xdr);
std::auto_ptr<catalog> copy (new catalog (ixdr));
I want to be able to specify a list of the classes that the serialized objects have (e.g. catalog, catalog, someOtherSerializableClass for 3 serialized objects) and store that information as a typedef
template <typename... Args>
struct variadic_typedef {};
typedef variadic_typedef<catalog, catalog, someOtherSerializableClass> myTypes;
as suggested in Is it possible to “store” a template parameter pack without expanding it?
and find a way to get a std::tuple to work with after the parsing has finished. A sketch:
auto serializedObjects(binaryParse<myTypes>(std::cin));
where serializedObjects would have the type
std::tuple<catalog, catalog, someOtherSerializableClass>
The trivial solution is not to use std::make_tuple(...) in the first place but to construct a std::tuple<...> directly: The order in which constructors for the members are called is well defined:
template <typename>
std::istream& dummy(std::istream& in) {
return in;
}
template <typename... T>
std::tuple<T...> parse(std::istream& in) {
return std::tuple<T...>(dummy<T>(in)...);
}
The function template dummy<T>() is only used to have something to expand on. The order is imposed by construction order of the elements in the std::tuple<T...>:
template <typename... T>
template <typename... U>
std::tuple<T...>::tuple(U...&& arg)
: members_(std::forward<U>(arg)...) { // NOTE: pseudo code - the real code is
} // somewhat more complex
Following the discussion below and Xeo's comment it seems that a better alternative is to use
template <typename... T>
std::tuple<T...> parse(std::istream& in) {
return std::tuple<T...>{ T(in)... };
}
The use of brace initialization works because the order of evaluation of the arguments in a brace initializer list is the order in which they appear. The semantics of T{...} are described in 12.6.1 [class.explicit.init] paragraph 2 stating that it follows the rules of list initialization semantics (note: this has nothing to do with std::initializer_list which only works with homogenous types). The ordering constraint is in 8.5.4 [dcl.init.list] paragraph 4.
As the comment says, you could just use initializer-list:
return std::tuple<args...>{args(stream)...};
which will work for std::tuple and suchlikes (which supports initializer-list).
But I got another solution which is more generic, and can be useful where initializer-list cannot be used. So lets solve this without using initializer-list:
template<typename... args>
std::tuple<args...> parse(std::istream &stream) {
return std::make_tuple(args(stream)...);
}
Before I explain my solution, I would like to discuss the problem first. In fact, thinking about the problem step by step would also help us to come up with a solution eventually. So, to simply the discussion (and thinking-process), lets assume that args expands to 3 distinct types viz. X, Y, Z, i.e args = {X, Y, Z} and then we can think along these lines, reaching towards the solution step-by-step:
First and foremost, the constructors of X, Y, and Z can be executed in any order, because the order in which function arguments are evaluated is unspecified by the C++ Standard.
But we want X to construct first, then Y, and Z. Or at least we want to simulate that behavior, which means X must be constructed with data that is in the beginning of the input stream (say that data is xData) and Y must be constructed with data that comes immediately after xData, and so on.
As we know, X is not guaranteed to be constructed first, so we need to pretend. Basically, we will read the data from the stream as if it is in the beginning of the stream, even if Z is constructed first, that seems impossible. It is impossible as long as we read from the input stream, but we read data from some indexable data structure such as std::vector, then it is possible.
So my solution does this: it will populate a std::vector first, and then all arguments will read data from this vector.
My solution assumes that each line in the stream contains all the data needed to construct an object of any type.
Code:
//PARSE FUNCTION
template<typename... args>
std::tuple<args...> parse(std::istream &stream)
{
const int N = sizeof...(args);
return tuple_maker<args...>().make(stream, typename genseq<N>::type() );
}
And tuple_maker is defined as:
//FRAMEWORK - HELPER ETC
template<int ...>
struct seq {};
template<int M, int ...N>
struct genseq : genseq<M-1,M-1, N...> {};
template<int ...N>
struct genseq<0,N...>
{
typedef seq<N...> type;
};
template<typename...args>
struct tuple_maker
{
template<int ...N>
std::tuple<args...> make(std::istream & stream, const seq<N...> &)
{
return std::make_tuple(args(read_arg<N>(stream))...);
}
std::vector<std::string> m_params;
std::vector<std::unique_ptr<std::stringstream>> m_streams;
template<int Index>
std::stringstream & read_arg(std::istream & stream)
{
if ( m_params.empty() )
{
std::string line;
while ( std::getline(stream, line) ) //read all at once!
{
m_params.push_back(line);
}
}
auto pstream = new std::stringstream(m_params.at(Index));
m_streams.push_back(std::unique_ptr<std::stringstream>(pstream));
return *pstream;
}
};
TEST CODE
///TEST CODE
template<int N>
struct A
{
std::string data;
A(std::istream & stream)
{
stream >> data;
}
friend std::ostream& operator << (std::ostream & out, A<N> const & a)
{
return out << "A" << N << "::data = " << a.data ;
}
};
//three distinct classes!
typedef A<1> A1;
typedef A<2> A2;
typedef A<3> A3;
int main()
{
std::stringstream ss("A1\nA2\nA3\n");
auto tuple = parse<A1,A2,A3>(ss);
std::cout << std::get<0>(tuple) << std::endl;
std::cout << std::get<1>(tuple) << std::endl;
std::cout << std::get<2>(tuple) << std::endl;
}
Output:
A1::data = A1
A2::data = A2
A3::data = A3
which is expected. See demo at ideone yourself. :-)
Note that this solution avoids the order-of-reading-from-the-stream problem by reading all the lines in the first call to read_arg itself, and all the later calls just read from the std::vector, using the index.
Now you can put some printf in the constructor of the classes, just to see that the order of construction is not same as the order of template arguments to the parse function template, which is interesting. Also, the technique used here can be useful for places where list-initialization cannot be used.
There's nothing special about make_tuple here. Any function call in C++ allows its arguments to be called in an unspecified order (allowing the compiler freedom to optimize).
I really don't suggest having constructors that have side-effects such that the order is important (this will be a maintenance nightmare), but if you absolutely need this, you can always construct the objects explicitly to set the order you want:
A a(std::cin);
std::tuple<A, B> t(std::make_tuple(a, B(std::cin)));
This answer comes from a comment I made to the template pack question
Since make_tuple deduces the tuple type from the constructed components and function arguments have undefined evaluation ordder, the construction has to happen inside the machinery, which is what I proposed in the comment. In that case, there's no need to use make_tuple; you could construct the tuple directly from the tuple type. But that doesn't order construction either; what I do here is construct each component of the tuple, and then build a tuple of references to the components. The tuple of references can be easily converted to a tuple of the desired type, provided the components are easy to move or copy.
Here's the solution (from the lws link in the comment) slightly modified, and explained a bit. This version only handles tuples whose types are all different, but it's easier to understand; there's another version below which does it correctly. As with the original, the tuple components are all given the same constructor argument, but changing that simply requires adding a ... to the lines indicated with // Note: ...
#include <tuple>
#include <type_traits>
template<typename...T> struct ConstructTuple {
// For convenience, the resulting tuple type
using type = std::tuple<T...>;
// And the tuple of references type
using ref_type = std::tuple<T&...>;
// Wrap each component in a struct which will be used to construct the component
// and hold its value.
template<typename U> struct Wrapper {
U value;
template<typename Arg>
Wrapper(Arg&& arg)
: value(std::forward<Arg>(arg)) {
}
};
// The implementation class derives from all of the Wrappers.
// C++ guarantees that base classes are constructed in order, and
// Wrappers are listed in the specified order because parameter packs don't
// reorder.
struct Impl : Wrapper<T>... {
template<typename Arg> Impl(Arg&& arg) // Note ...Arg, ...arg
: Wrapper<T>(std::forward<Arg>(arg))... {}
};
template<typename Arg> ConstructTuple(Arg&& arg) // Note ...Arg, ...arg
: impl(std::forward<Arg>(arg)), // Note ...
value((static_cast<Wrapper<T>&>(impl)).value...) {
}
operator type() const { return value; }
ref_type operator()() const { return value; }
Impl impl;
ref_type value;
};
// Finally, a convenience alias in case we want to give `ConstructTuple`
// a tuple type instead of a list of types:
template<typename Tuple> struct ConstructFromTupleHelper;
template<typename...T> struct ConstructFromTupleHelper<std::tuple<T...>> {
using type = ConstructTuple<T...>;
};
template<typename Tuple>
using ConstructFromTuple = typename ConstructFromTupleHelper<Tuple>::type;
Let's take it for a spin
#include <iostream>
// Three classes with constructors
struct Hello { char n; Hello(decltype(n) n) : n(n) { std::cout << "Hello, "; }; };
struct World { double n; World(decltype(n) n) : n(n) { std::cout << "world"; }; };
struct Bang { int n; Bang(decltype(n) n) : n(n) { std::cout << "!\n"; }; };
std::ostream& operator<<(std::ostream& out, const Hello& g) { return out << g.n; }
std::ostream& operator<<(std::ostream& out, const World& g) { return out << g.n; }
std::ostream& operator<<(std::ostream& out, const Bang& g) { return out << g.n; }
using std::get;
using Greeting = std::tuple<Hello, World, Bang>;
std::ostream& operator<<(std::ostream& out, const Greeting &n) {
return out << get<0>(n) << ' ' << get<1>(n) << ' ' << get<2>(n);
}
int main() {
// Constructors run in order
Greeting greet = ConstructFromTuple<Greeting>(33.14159);
// Now show the result
std::cout << greet << std::endl;
return 0;
}
See it in action on liveworkspace. Verify that it constructs in the same order in both clang and gcc (libc++'s tuple implementation holds tuple components in the reverse order to stdlibc++, so it's a reasonable test, I guess.)
To make this work with tuples which might have more than one of the same component, it's necessary to modify Wrapper to be a unique struct for each component. The easiest way to do this is to add a second template parameter, which is a sequential index (both libc++ and libstdc++ do this in their tuple implementations; it's a standard technique). It would be handy to have the "indices" implementation kicking around to do this, but for exposition purposes, I've just done a quick-and-dirty recursion:
#include <tuple>
#include <type_traits>
template<typename T, int I> struct Item {
using type = T;
static const int value = I;
};
template<typename...TI> struct ConstructTupleI;
template<typename...T, int...I> struct ConstructTupleI<Item<T, I>...> {
using type = std::tuple<T...>;
using ref_type = std::tuple<T&...>;
// I is just to distinguish different wrappers from each other
template<typename U, int J> struct Wrapper {
U value;
template<typename Arg>
Wrapper(Arg&& arg)
: value(std::forward<Arg>(arg)) {
}
};
struct Impl : Wrapper<T, I>... {
template<typename Arg> Impl(Arg&& arg)
: Wrapper<T, I>(std::forward<Arg>(arg))... {}
};
template<typename Arg> ConstructTupleI(Arg&& arg)
: impl(std::forward<Arg>(arg)),
value((static_cast<Wrapper<T, I>&>(impl)).value...) {
}
operator type() const { return value; }
ref_type operator()() const { return value; }
Impl impl;
ref_type value;
};
template<typename...T> struct List{};
template<typename L, typename...T> struct WrapNum;
template<typename...TI> struct WrapNum<List<TI...>> {
using type = ConstructTupleI<TI...>;
};
template<typename...TI, typename T, typename...Rest>
struct WrapNum<List<TI...>, T, Rest...>
: WrapNum<List<TI..., Item<T, sizeof...(TI)>>, Rest...> {
};
// Use WrapNum to make ConstructTupleI from ConstructTuple
template<typename...T> using ConstructTuple = typename WrapNum<List<>, T...>::type;
// Finally, a convenience alias in case we want to give `ConstructTuple`
// a tuple type instead of a list of types:
template<typename Tuple> struct ConstructFromTupleHelper;
template<typename...T> struct ConstructFromTupleHelper<std::tuple<T...>> {
using type = ConstructTuple<T...>;
};
template<typename Tuple>
using ConstructFromTuple = typename ConstructFromTupleHelper<Tuple>::type;
With test here.
I believe the only way to manually unroll the definition. Something like the following might work. I welcome attempts to make it nicer though.
#include <iostream>
#include <tuple>
struct A { A(std::istream& is) {}};
struct B { B(std::istream& is) {}};
template <typename... Ts>
class Parser
{ };
template <typename T>
class Parser<T>
{
public:
static std::tuple<T> parse(std::istream& is) {return std::make_tuple(T(is)); }
};
template <typename T, typename... Ts>
class Parser<T, Ts...>
{
public:
static std::tuple<T,Ts...> parse(std::istream& is)
{
A t(is);
return std::tuple_cat(std::tuple<T>(std::move(t)),
Parser<Ts...>::parse(is));
}
};
int main()
{
Parser<A,B>::parse(std::cin);
return 1;
}

Translating a std::tuple into a template parameter pack

I have a
typedef std::tuple<A, B> TupleType;
and would like to use the list of classes
for a "template".
Suppose I have:
template<typename... args>
std::tuple<args...> parse(std::istream &stream) {
return std::make_tuple(args(stream)...);
}
and that I can successfully use it with:
auto my_tuple = parse<A, B>(ifs);
is it possible to avoid having to specify the class list A,B if I already have a
typedef std::tuple<A,B> TupleType;
where the list A,B is already present?
an example:
#include <cstdlib> // EXIT_SUCCESS, EXIT_FAILURE
#include <iostream> // std::cerr
#include <fstream> // std::ifstream
#include <tuple> // std::tuple
class A {
public:
A(std::istream &); // May throw FooBaarException
};
class B {
public:
B(std::istream &); // May throw FooBaarException
};
template<typename... args>
std::tuple<args...> parse(std::istream &stream) {
return std::make_tuple(args(stream)...);
}
int main() {
std::ifstream ifs;
ifs.exceptions(ifstream::eofbit | ifstream::failbit | ifstream::badbit);
int res = EXIT_FAILURE;
try {
ifs.open("/some/file/path", std::ios::in | std::ios::binary);
auto my_tuple = parse<A, B>(ifs); // my_tuple is of the type std::tuple<A,B>
/* Here do something interesting with my_tuple */
res = EXIT_SUCCESS;
} catch (ifstream::failure e) {
std::cerr << "error: opening or reading file failed\n";
} catch (FooBaarException e) {
std::cerr << "error: parsing in a constructor failed\n";
}
return res;
}
The underlying problem in your situation seems to be that you'd like to specialize the function template parse for the special case when the template argument is a std::tuple. Unfortunately, this kind of specialization isn't possible with function templates.
However, it is possible with class templates.
So, as a first step, you could define parse as a static function of a struct, like this:
using std::istream;
using std::tuple;
using std::make_tuple;
struct A { A(const istream &) {} };
struct B { B(const istream &) {} };
template <typename... Args>
struct parser
{
/* Your original function, now inside a struct.
I'm using direct tuple construction and an
initializer list to circumvent the order-of-
construction problem mentioned in the comment
to your question. */
static tuple<Args...> parse(const istream &strm)
{ return tuple<Args...> {Args(strm)...}; }
};
template <typename... Args>
struct parser<tuple<Args...>>
{
/* Specialized for tuple. */
static tuple<Args...> parse(const istream &strm)
{ return parser<Args...>::parse(strm); }
};
You can then call it in the desired way:
int main()
{
typedef tuple<A,B> tuple_type;
auto tup = parser<tuple_type>::parse(std::cin);
return 0;
}
As a second step, you can define a function template (again) which passes the arguments on to the right specialization of the struct:
template <typename... Args>
auto parse(const istream &strm) -> decltype(parser<Args...>::parse(strm))
{ return parser<Args...>::parse(strm); }
And now you can use it in exactly the way you wanted:
int main()
{
typedef tuple<A,B> tuple_type;
auto tup = parse<tuple_type>(std::cin);
return 0;
}
(And you can still use it in the old way, too: auto tup = parse<A,B>(std::cin).)
Remark. As mentioned in the comment to parser::parse(), I used direct tuple construction instead of make_tuple to avoid problems with the order of construction of the tuple elements. This is not directly related to your question, but a good thing to do. See how to avoid undefined execution order for the constructors when using std::make_tuple.
There is a standard idiom for this kind of thing. [1]
// Define the "shape" of the template
template<typename Tuple> struct TupleMap;
// Specialize it for std::tuple
template<typename...T> struct TupleMap<std::tuple<T...>> {
using type = std::tuple<T...>; // not necessary but saves typing
// ... inside here, you have access to the parameter pac
}
Here's an example of using it, which might or might not fit your expectations (your example doesn't really indicate your expected use, since it lacks the typedef you promise in your question): liveworkspace.org.
Since litb raised the point, it is possible to force the tuple-components to be constructed in left-to-right order, illustrating another interesting idiom: comb inheritance. See lws.
(Since lws might disappear again, who knows, I'll paste the code here as well):
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
// Define the "shape" of the template
template<typename Tuple> struct TupleMap;
// Specialize it for std::tuple
template<typename...T> struct TupleMap<std::tuple<T...>> {
using type = std::tuple<T...>; // not necessary but saves typing
type value;
template<typename Arg>
TupleMap(Arg&& arg)
: value(T(std::forward<Arg>(arg))...) {
}
operator type() { return value; }
};
//Try it out:
using std::get; // Note 2
using Numbers = std::tuple<char, double, int>;
// Note 3
std::ostream& operator<<(std::ostream& out, const Numbers& n) {
return out << get<0>(n) << ' ' << get<1>(n) << ' ' << get<2>(n);
}
int main() {
std::cout << TupleMap<Numbers>(93.14159);
return 0;
}
[1] At least, I think it's a standard idiom. I use it a lot, and think of it as the "can-opener" pattern.
[2] This is needed (or at least, it's my style) to allow the use of get with tuple-like templates defined outside of std. Doing it this way allows ADL to find the appropriate definition of get without forcing me to add specializations to std::get. In this way, it's similar to the standard ADL idiom for begin and end.
[3] You can search SO for a cool hack to specialize operator<< for all tuples. There's a simpler one which can be used for specific tuples, but that's all off-topic for this question, so I just did something easy and dependency free. Note that this works because of the conversion operator in TupleMap
The basic approach is to create a sequence of indices 0, ..., std::tuple_size<Tuple>::value - 1 as a parameter pack Indices and call your function with parse<typename std::tuple_element<Tuple, Indices>::type...>(stream). You'd probably encapsulate the logic into a function parse_tuple<Tuple>(stream) (and some function this one delegates to) which in the end delegates to parse<...>(stream).
First, here is a class template and a function to create a sequence of indices based on the size of a std::tuple. The indices are needed to obtain a list of type from std::tuple:
template <int... Indices> struct indices;
template <>
struct indices<-1> { // for an empty std::tuple<> there is no entry
typedef indices<> type;
};
template <int... Indices>
struct indices<0, Indices...> { // stop the recursion when 0 is reached
typedef indices<0, Indices...> type;
};
template <int Index, int... Indices>
struct indices<Index, Indices...> { // recursively build a sequence of indices
typedef typename indices<Index - 1, Index, Indices...>::type type;
};
template <typename T>
typename indices<std::tuple_size<T>::value - 1>::type const*
make_indices() {
return 0;
}
With this in place, it is quite easy to extract the sequence of types from a std::tuple<T...>:
template<typename T, int... Indices>
T parse_tuple(std::istream &stream, indices<Indices...> const*) {
return parse<typename std::tuple_element<Indices, T>::type...>(stream);
}
template <typename T>
T parse_tuple(std::istream& stream) {
return parse_tuple<T>(stream, make_indices<T>());
}

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.