3

I have a templated class A in which I want to call a templated function from another class B

the header looks like :

template<typename... T> class A
{
public:
    A();
    void get(type_X params);
private:
    B b_;
};

and the .hxx :

template<typename... T> void A<T...>::get(type_X params)
{
    /*here lies my problem*/
    T... variable; // just like we would do string s;
                   // and pass it to a function f(string& s) to assign it
    b_.get(params, variable...);
    /* do something with updated value of variable */
}

where member b_ (class B) has a templated function get which looks like

template<typename... T> int B<T...>::get(type_X params, const T&... variable)
{
    /* change variable, just like we would assign a new value to a string& */
    return 0; 
}

And I have no idea how to initialize (if possible) my "T..." object to be given as argument to templated function B::get.

Thanks for your help

Thibaut
  • 133
  • 1
  • 10

3 Answers3

3

First off, the indices machinery to create a pack of integral indices at compile time:

template< std::size_t... Ns >
struct indices {
    typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices {
    typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 > {
    typedef indices<> type;
};

Now, you can create an array of objects:

T vars[] = { T()... };

Next, you need a helper function to create a context where you can deduce the pack of integers. Something like this:

template<typename... T, T, size_t... I>
int helper(type_X params, T* arr, indices<I...>)
{
    return b_.get(params, arr[I]...);
}

For arr parameter you'd pass the array vars you created previously and for the last one you pass make_indices<sizeof...(T)>::type().

Hope that helps.

jrok
  • 54,456
  • 9
  • 109
  • 141
  • Actually I need to retrieve the modified object variable, this was not clear in my post I am going to edit it. – Thibaut Jan 28 '14 at 18:01
  • Your answer made my code compile, but if I understand correctly this does not allow me to retrieve an updated T... object I could use in A::get scope ? – Thibaut Jan 28 '14 at 18:12
  • I changed my answer accordingly. Hope that suits your needs. – jrok Jan 28 '14 at 18:13
  • Why do I need to create an array container with (in my case) only one element ? Your previous temporary T()... syntax cannot work to initialize the unique object I need ? – Thibaut Jan 28 '14 at 18:21
  • Unless the size of this array represents the number of element in my T... object ? – Thibaut Jan 28 '14 at 18:27
  • Yes, the size of the array will be deduced by the size of `T...` pack. If there's only one element, the array's size will be 1. – jrok Jan 28 '14 at 18:30
  • I can't use std::initializer_list as I have different types (int, int, std::string, std::string) as T... – Thibaut Jan 28 '14 at 18:55
  • Your method works fine, it looks a lot like what a coworker does when dealing with templating methods inspirated by functional programation, but I realize my design is not right as it won't allow me to do what I intended to :( – Thibaut Jan 29 '14 at 09:04
1

First off, this is invalid syntax:

T... variable;

To do something like this, you need to create a tuple:

std::tuple<T...> variable;

And then you use one of the techniques to call a function with the tuple members as parameters:

"unpacking" a tuple to call a matching function pointer Pass tuple's content as variadic function arguments How do I expand a tuple into variadic template function's arguments?

Community
  • 1
  • 1
Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • Yes I know this is invalid, I wanted to do something similar. But I don't even know if this exists. Tuple seem to work, but as I told jrok my design was not correct, but thanks anyway this is a solution to the problem I exposed. – Thibaut Jan 29 '14 at 10:06
  • Using your tuple allows me to solve my problem _theoricaly_ : `sorry, unimplemented: cannot expand ‘T ...’ into a fixed-length argument list` :) I need a new compiler .. – Thibaut Jan 29 '14 at 13:28
  • Yes, you do. Or a newer standard library at least, because tuple's argument list shouldn't be fixed length. – Sebastian Redl Jan 29 '14 at 13:51
0

Following may help you:

#if 1 // Not in C++11
// Helper class to be able to use expansion of std::get<Index>(tuple)
template <int... Is> struct index_sequence {};

// Following create index_sequence<0, 1, 2, .., sizeof...(Is) - 1>
template <int Index, int... Is>
struct make_index_sequence { // recursively build a sequence of indices
    typedef typename make_index_sequence<Index - 1, Index -1, Is...>::type type;
};

template <int... Is>
struct make_index_sequence<0, Is...> { // stop the recursion when 0 is reached
    typedef index_sequence<Is...> type;
};
#endif

template<typename... Ts> class A
{
public:
    void get(type_X params)
    {
        std::tuple<Ts...> t;
        a.get(params, t, make_index_sequence<sizeof...(Ts)>());
    }
private:
    template<std::size_t ... Is>
    void get(type_X params, std::tuple<Ts...>& t, index_sequence<Is...>)
    {
        b_.get(params, std::get<Is>(t)...);
    }

private:
    B b_;
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302