thor
thor

Reputation: 22460

variadic template template parameter syntax

I have this template function (I remember seeing similar things somewhere from SO). It works on both std::function and std::list (as Container). But I can't really understand the syntax template <typename, typename...> class Container. What's in the < > seems to be a different language (compared to C/old C++). Can someone please explain it or give a good reference that explains this?

template <typename T, template <typename, typename...> class Container>
static bool contained(const T & x, const Container<T> & xs) {
    return std::find(xs.begin(),xs.end(),x) != xs.end();
}

Upvotes: 1

Views: 130

Answers (1)

Praetorian
Praetorian

Reputation: 109089

template <typename T, template <typename, typename...> class Container>

The above indicates that Container is a template template-parameter, which means that the Container type that you pass to the function template must itself be a template that takes at least one template argument - the second template argument onwards will be consumed by the parameter pack (typename...).

But there's a problem with your function template. As I explained, you indicate that Container must be a class template that takes one or more template arguments, but then the corresponding function parameter (xs) indicates it takes a single template argument. The reason this works with std::list, or std::vector, or std::deque is because their respective second template arguments, the allocator type, has a default value (std::allocator<T>). Your function template will not work with one of these containers if they have a non-default allocator type.

To fix it, the type of xs needs to accommodate the extra template arguments also.

template <typename T, typename... Params, 
          template <typename, typename...> class Container>
static bool contained(const T & x, const Container<T, Params...> & xs) {
    return std::find(xs.begin(),xs.end(),x) != xs.end();
}

This particular problem can, however, be solved without the use of template template parameters. Just accept any type Container instead of placing stipulations on it being a template. The type of the element you're searching for can be specified by using the Container::value_type nested type that all containers in the standard library define.

template <typename Container>
static bool contained(typename Container::value_type const& x, 
                      const Container& xs) {
    return std::find(xs.begin(),xs.end(),x) != xs.end();
}

Also, C++11 added std::any_of which does the same thing as your contained() function.

Upvotes: 2

Related Questions