2

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 specified by a variadic template. Access to vector can then 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;
}
Mihai Galos
  • 1,707
  • 1
  • 19
  • 38

1 Answers1

5

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);
// ^^^^^^^^
Quentin
  • 62,093
  • 7
  • 131
  • 191