7

Being stuck in TR1 land, for a test program I need to perform certain operations on a number of objects of specific types. I have a couple of tuple type definitions which look like this:

typedef std::tr1::tuple< bool
                       , signed char
                       , signed short
                       , signed int
                       , signed long long
                       , unsigned char
                       , unsigned short
                       , unsigned int
                       , unsigned long long >  integral_types;

From each tuple type an object is to be created. I then have function templates similar to this:

template<typename T>
void invoke_operation_1(T& obj);

These need to be called for all objects in a tuple object.

How do I do that in C++03?

sbi
  • 219,715
  • 46
  • 258
  • 445

3 Answers3

8

There was a feature just finalized in Bristol for C++14 to address this very problem. It's not too hard to deal with.

For the simpler case, you can use a recursive template. It's a smidge of a mess though without partial function specialization and such.

template<typename Tup, std::size_t N> struct visit_detail {
     template<typename F> static void call(Tup& t, F f) {
         f(std::tr1::get<N>(t));
         return visit_detail<Tup, N+1>::call(t, f);
     }
};
template<typename Tup> struct visit_detail<Tup, std::tr1::tuple_size<Tup>::value> {
    template<typename F> static void call(Tup& t, F f) {}
}

template<typename Tup, typename F> void visit(Tup& t, F f) {
    return visit_detail<Tup, 0>::call(t, f);
}

Here f can be hardcoded or a parameter function object or whatever you want.

Puppy
  • 144,682
  • 38
  • 256
  • 465
3

You could use boost::fusion if you need to call the same templated function for every object in the tuple. E.g.

template<typename T>
void invoke_operation_1(T& obj)
{
    std::cout << obj << std::endl;
}

struct executor
{
    template<typename T>
    void operator()(T& t) const
    {
        invoke_operation_1(t);
    }
};

typedef boost::tuple< bool
                       , signed char
                       , signed short
                       , signed int
                       , signed long long
                       , unsigned char
                       , unsigned short
                       , unsigned int
                       , unsigned long long >  integral_types;
int main()
{
    integral_types t(true, 0, 1, 2, 3, 4, 5, 6, 7);
    boost::fusion::for_each(t, executor());
    return 0;
}
mkaes
  • 13,781
  • 10
  • 52
  • 72
  • I was hesitant to bring in boost::fusion just to do that, but this looks really convenient, so I might give it a try anyway. What conditions must `executor` meet? Would some `std::tr1::bind()` expression work instead? With argument placeholders? – sbi May 03 '13 at 14:26
  • @sbi The docuentation says a `Regular Callable Object` so a bind expression should ok. – mkaes May 03 '13 at 14:32
  • @sbi since `invoke_operation_1` is a template and not a function, I doubt `boost::bind` will work. At least I could not find any overloads taking template template arguments, which would be needed here. – Arne Mertz May 03 '13 at 14:38
  • @ArneMertz: You got a point there, I just ran into this. `:)` Well, then I'll just have to wrap it into a function object, I think. Thanks, @mkaes! – sbi May 03 '13 at 14:41
  • Well, since in the end I did indeed use fusion, I accepted this answer. Thanks to everyone who put effort into this! – sbi May 03 '13 at 15:20
0
template<typename tup, typename N>
struct visit_detailImpl {
    template<typename f>
    static void call(tup& t, f f) {
        f(std::tr1::get<N::value>(t));
        return visit_detailImpl<tup, std::integral_constant<std::size_t, N::value + 1> >::call(t, f);
    }
};
template<typename tup> // end recursion struct
struct visit_detailImpl<tup, std::integral_constant<std::size_t, std::tr1::tuple_size<tup>::value> > {
    template<typename f>
    static void call(tup& t, f f) {}
};
template<typename tup, typename Fn>
void for_each_tup(tup& t, Fn f) {
    return visit_detailImpl<tup, std::integral_constant<std::size_t, 0> >::call(t, f);
}