Mihai Galos Mihai Galos - 2 months ago 22
C++ Question

Wrap variadic template to vector of tuples

Using C++14, I'm trying to extend this implementation to support an ObserverCallback method which will be called externally.

The MyClass container uses a vector of tuples, whose types are specivied by a variadic template. Access to vector them can be done using access < T >().

What I need is to implement an observer which should add elements to the vector. Since the type of the element can be any of the types in the tuple, I've templated it as well:

template <typename ...T>
class Wrapper{
public:
MyClass<T...> mc;

template <typename U>
void ObserverCallback(const U& element){
mc.access<U>().push_back(element);
}
};


There seems to be an error in the Wrapper class:

variadic2.cpp: In member function 'void Wrapper<T>::ObserverCallback(const U&)':
variadic2.cpp:71:20: error: expected primary-expression before '>' token
mc.access<U>().push_back(element);
^
variadic2.cpp:71:22: error: expected primary-expression before ')' token
mc.access<U>().push_back(element);
^
variadic2.cpp: In function 'int main(int, char**)':
variadic2.cpp:87:10: error: 'class MyClass<float, std::reference_wrapper<int>, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >' has no member named 'ObserverCallback'
w.mc.ObserverCallback(string("a"));


For reference, I'm also attaching the full source listing:

#include <tuple>
#include <vector>
#include <functional>
#include <iostream>
#include <string>

using namespace std;

template <class T1, class T2>
struct SameType
{
static const bool value = false;
};

template<class T>
struct SameType<T, T>
{
static const bool value = true;
};

template <typename... Types>
class MyClass
{
public:
typedef tuple<vector<Types>...> vtype;
vtype vectors;

template<int N, typename T>
struct VectorOfType: SameType<T,
typename tuple_element<N, vtype>::type::value_type>
{ };

template <int N, class T, class Tuple,
bool Match = false> // this =false is only for clarity
struct MatchingField
{
static vector<T>& get(Tuple& tp)
{
// The "non-matching" version
return MatchingField<N+1, T, Tuple,
VectorOfType<N+1, T>::value>::get(tp);
}
};

template <int N, class T, class Tuple>
struct MatchingField<N, T, Tuple, true>
{
static vector<T>& get(Tuple& tp)
{
return std::get<N>(tp);
}
};

template <typename T>
vector<T>& access()
{
return MatchingField<0, T, vtype,
VectorOfType<0, T>::value>::get(vectors);
}
};

template <typename ...T>
class Wrapper{
public:
MyClass<T...> mc;

template <typename U>
void ObserverCallback(const U& element){
mc.access<U>().push_back(element);
}
};

int main( int argc, char** argv )
{
int twelf = 12.5;
typedef reference_wrapper<int> rint;

Wrapper<float, rint, string> w;
vector<rint>& i = w.mc.access<rint>();

i.push_back(twelf);

w.mc.access<float>().push_back(10.5);

w.ObserverCallback(string("a"));

cout << "Test:\n";
cout << "floats: " << w.mc.access<float>()[0] << endl;
cout << "ints: " << w.mc.access<rint>()[0] << endl;
cout << "strings: " << w.mc.access<string>()[0] << endl;
//w.access<double>();

return 0;
}

Answer Source

mc's type depends on T..., so you must specify that its access member should be a function template:

mc.template access<U>().push_back(element);
// ^^^^^^^^