razvanp
razvanp

Reputation: 178

Template metaprogramming list

I want to build a simple TList using template meta-programming and I have two questions for why it is not working. Here is the code:

struct TNull{};

template<typename T,typename U>
struct TList
{
    typedef T THead;
    typedef U TTail;

    THead head;
    TTail tail;
};

template<typename T>
void Foo(TList<T,TNull> &list)
{
    std::cout<<list.head<<"  ";
}

template<typename T,typename U>
void Foo(TList<T,U> &list)
{
    std::cout<<list.head<<" ";
    //Foo<int,TNull>(list.tail);  // COMM_1
    Foo<decltype(list.tail.head),decltype(list.tail.tail)>(list.tail); //COMM_2
}


int main (int argc, const char * argv[])
{
    TList<int,TList<int,TNull>> list;
    Foo(list);
    return 0;
}

First, I would like to know how to write the COMM_2 line so the template will expand until it reaches the TNull then it stops. I tried different methods and none of it works

The second question is if I write the expansion by myself (like in COMM_1) I expect the compiler to pick the first Foo overload but it doesn't, it gives me an error. Why is this behavior? I was expecting the compiler to pick the best match for a specific set of arguments.

I am testing this feature using Visual c++ 2010, which has no support for variadic template arguments, and this is for a project at my workplace so switching compilers is not an option for me.

Upvotes: 0

Views: 946

Answers (1)

Ambroz Bizjak
Ambroz Bizjak

Reputation: 8095

Simply call Foo(list.tail). The compiler will determine the function to call and deduce the template parameters based on the types of the function arguments. This code works in gcc under -std=c++98, and prints "1 2 \n".

#include <iostream>

struct TNull{};

template<typename T,typename U>
struct TList {
    typedef T THead;
    typedef U TTail;

    THead head;
    TTail tail;
};

template<typename T>
void Foo(TList<T,TNull> &list)
{
    std::cout << list.head << "  ";
}

template<typename T,typename U>
void Foo(TList<T,U> &list)
{
    std::cout << list.head << " ";
    Foo(list.tail);
}

int main (int argc, const char * argv[])
{
    TList<int,TList<int,TNull> > list;
    list.head = 1;
    list.tail.head = 2;
    Foo(list);
    std::cout << "\n";
    return 0;
}

Note that this will not work with empty lists. For that, you should write your Foo functions so that the base case is a TNull, as opposed to a TList with a TNull tail.

Upvotes: 2

Related Questions