Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declare template function to accept any container but only one contained type

Tags:

c++

templates

stl

I want to declare a function that accepts different STL containers, but they must contain objects of a specific class (e.g. it should accept std::vector<double> and std::deque<double> but no std::vector<std::string>).

I have found answers for templating both the container and the contained types, but my attempts to adapt them so that the contained type is fixed have been unsuccessful.

like image 523
user2891462 Avatar asked Sep 29 '17 08:09

user2891462


1 Answers

You can do it with template template arguments (no typo). The first template argument of your template function is another template with a variadic number of template arguments. The second template argument are the variadic template arguments. In the signature you then fix the first template argument to the type you want (e.g. double) and let the compiler deduce the rest.

#include <deque>
#include <iostream>
#include <string>
#include <vector>

template < template < class ... > class Container, class ... Args >
void any_container(Container<double, Args...>)
{
    // print what was deduced
    std::cout << __PRETTY_FUNCTION__ << '\n';
}

int main()
{
    std::vector<double> vd;
    any_container(vd);

    std::deque<double> dd;
    any_container(dd);

    std::vector<std::string> vs;
    any_container(vs); // BOOM!
}

@PasserBy already hinted a different solution in this comment. Instead of having a substitution failure you could also just take the container as a template argument and the query its value_type in a static_assert. This has the advantage that you can put a custom error message.

#include <deque>
#include <iostream>
#include <string>
#include <type_traits>
#include <vector>

template <typename Container> void any_container(Container)
{
    static_assert(std::is_same<typename Container::value_type, double>::value,
                  "BOOM!");
    // print what was deduced
    std::cout << __PRETTY_FUNCTION__ << '\n';
}

int main()
{
    std::vector<double> vd;
    any_container(vd);

    std::deque<double> dd;
    any_container(dd);

    std::vector<std::string> vs;
    any_container(vs); // BOOM!
}
like image 173
Henri Menke Avatar answered Oct 03 '22 03:10

Henri Menke