4

I would like to have a type, that would be in effect POD but I would like to be able to specify how and which types are in it, for example:

template<Args...>
struct POD
{
//here I would like to create depending on Args appropriate types as a members.
};

Is it possible to do it with this new variadic templates feature in C++0x?

There is nothing we can do
  • 23,727
  • 30
  • 106
  • 194

2 Answers2

0

I’ve never yet used the C++0x variadic templates feature but the following code compiles on G++ 4.5:

template <typename... Args>
struct tuple;

template <typename T, typename... Args>
struct tuple<T, Args...> {
    T value;
    tuple<Args...> inner;
};

template <typename T>
struct tuple<T> {
    T value;
};

However, initializing them is … weird because we need to nest the inner values:

int main() {
    tuple<int> n1 = { 23 };
    tuple<int, float> n2 = { 42, { 0.5f } };
    tuple<std::string, double, int> n3 = { "hello, world", { 3.14, { 97 } } };
}

Retrieving the values is of course a bit tedious. The simplest method is probably to provide a get<N>() function template.

But we cannot implement get directly since function templates cannot be partially specialized. Either we need to use SFINAE (read: boost::enable_if) or we need to delegate the actual function of get to a type that can be partially specialized.

In the following, I did the latter. But first, we need another helper type trait: nth_type, which returns the appropriate return type of the get function:

template <unsigned N, typename... Args>
struct nth_type;

template <unsigned N, typename T, typename... Args>
struct nth_type<N, T, Args...> : nth_type<N - 1, Args...> { };

template <typename T, typename... Args>
struct nth_type<0, T, Args...> {
    typedef T type;
};

Easy-peasy. Just returns the nth type in a list of types.

Now we can write our get function:

template <unsigned N, typename... Args>
inline typename nth_type<N, Args...>::type get(tuple<Args...>& tup) {
    return get_t<N, Args...>::value(tup);
}

Like I said, this just delegates the task. No biggie. In practice, we probably want to have another overload for const tuples (but then, in practice we would use an existing tuple type).

Now for the killing, followed by a light salad:

template <unsigned N, typename... Args>
struct get_t;

template <unsigned N, typename T, typename... Args>
struct get_t<N, T, Args...> {
    static typename nth_type<N, T, Args...>::type value(tuple<T, Args...>& tup) {
        return get_t<N - 1, Args...>::value(tup.inner);
    }
};

template <typename T, typename... Args>
struct get_t<0, T, Args...> {
    static T value(tuple<T, Args...>& tup) {
        return tup.value;
    }
};

And that’s it. We can test this by printing some values in our previously defined variables:

std::cout << get<0>(n1) << std::endl; // 23
std::cout << get<0>(n2) << std::endl; // 42
std::cout << get<0>(n3) << std::endl; // hello, world

std::cout << get<1>(n2) << std::endl; // 0.5
std::cout << get<1>(n3) << std::endl; // 3.14

std::cout << get<2>(n3) << std::endl; // 97

Man, it’s fun messing with variadic templates.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • I was so sure that the composed member would *necessarily* be non-POD, thus making the type itself non-POD, that I had completely ruled out this solution :) – icecrime Nov 26 '10 at 12:58
  • There'a a std::tuple that also provides get, I believe. – Puppy Nov 26 '10 at 13:23
  • @DeadMG: of course. This is just to show how it would be done, not to create production code. That said, is `std::tuple` a POD? – Konrad Rudolph Nov 26 '10 at 13:25
  • **Nota bene:** Of course, the above `tuple` class is only a POD if every of its template arguments is a POD. The third example uses `std::string` and consequently isn’t a POD. – Konrad Rudolph Nov 26 '10 at 13:26
  • If all it's arguments are PODs, then yes. – Puppy Nov 26 '10 at 14:30
0

Are you familiar with std::tuple?

AFAIK it's a POD if all it's members are PODs, if I'm wrong then I'm guessing it isn't possible.

Motti
  • 110,860
  • 49
  • 189
  • 262