3

I have the following code that works fine:

list <Politician> MakeList ( int num, ... ){ va_list arguments; va_start ( arguments, num ); list <Politician> PoliticianList; for ( int x = 0; x < num; x++ ) { PoliticianList.push_back(va_arg (arguments, Politician)); } va_end ( arguments ); return PoliticianList; } 

However, when trying to make it generic:

template<class TYPE> list <TYPE> MakeList ( int num, ... ){ va_list arguments; va_start ( arguments, num ); list <TYPE> PoliticianList; for ( int x = 0; x < num; x++ ) { PoliticianList.push_back(va_arg (arguments, TYPE)); } va_end ( arguments ); return PoliticianList; } 

I get the following error when compiling:

error C2783: 'std::list<TYPE> MakeList(int,...)' : could not deduce template argument for 'TYPE' 

How can I make it generic, so I won't have to re-implement for a different class objects?

7
  • 2
    How are you calling that function? Commented May 24, 2013 at 20:05
  • A variadic template would be a better option if you have C++11. Commented May 24, 2013 at 20:05
  • 1
    You have to say MakeList<Foo>(3, foo1, foo2, foo3). Commented May 24, 2013 at 20:07
  • I can not reproduce your problem: Live Code. How do you using MakeList ? Commented May 24, 2013 at 20:08
  • MakeList<Foo>(3, foo1, foo2, foo3) Commented May 24, 2013 at 20:14

1 Answer 1

3

You need to explicitly provide a template argument for TYPE when invoking the templated version of MakeList, because the compiler doesn't know, based only on the arguments you are providing, what TYPE should be. For instance, given the following call:

MakeList<Politician>(3, politician1, politician2, politician3) 

There is no way the compiler could deduce what TYPE is. If you are expecting it to be clever enough and deduce that you are passing objects of type Politician as arguments, well that won't work: C-style variadic functions simply do not provide that information at compile time.

However, in C++11 you could use variadic templates for this purpose, which among other thing would allows you not to pass in the number of subsequent arguments as the first argument. Here is a possible way you could rewrite your variadic MakeList():

namespace detail { template<typename T> void MakeList(std::list<typename std::remove_reference<T>::type>& l, T&& elem) { l.push_back(std::forward<T>(elem)); } template<typename T, typename... Ts> void MakeList( std::list<typename std::remove_reference<T>::type>& l, T&& elem, Ts&&... elems) { l.push_back(std::forward<T>(elem)); MakeList(l, std::forward<Ts>(elems)...); } } template<typename T, typename... Ts> std::list<typename std::remove_reference<T>::type> MakeList( T&& elem, Ts&&... elems) { std::list<typename std::remove_reference<T>::type> l; detail::MakeList(l, std::forward<T>(elem), std::forward<Ts>(elems)...); return l; } 

You could then use it this way:

int main() { Politician p1{"John", "Smith"}; Politician p2{"Mike", "Black"}; Politician p3{"George", "White"}; std::list<Politician> myList = MakeList(p1, p2, p3); for (auto const& p : myList) { std::cout << p.name << " " << p.surname << std::endl; } } 

Here is a live example.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.