user9985127
user9985127

Reputation: 195

How to pass the name of a template class to a template argument?

I know we can do the following,

template <class CONTAINER>
void f(CONTAINER *c){}

int main(){
    std::vector<int> v;
    f(&v);
    std::set<int> s;
    f(&s);
}

Then, I want an alternative (convenient for my project), like the following,

template <class CONTAINER>
void f(CONTAINER<int> *c){} // the CONTAINER is the name of a template class

But, the compiler outputs

error: ‘CONTAINER’ is not a template

Is this possible?

Upvotes: 4

Views: 891

Answers (1)

Thomas Sablik
Thomas Sablik

Reputation: 16448

You are looking for a template template parameter:

#include <set>
#include <vector>

template<template<typename> typename CONTAINER>
void f(CONTAINER<int> *){}

int main(){
    std::vector<int> v;
    f(&v);
    std::set<int> s;
    f(&s);
}

"Matching template template parameters to compatible arguments" is a C++17 feature. This won't work with C++14 because std::vector has more than one template parameter.

You need -frelaxed-template-template-args to compile this code with Clang, see: Template template parameter in function templates and How is P0522R0 breaking code?

An alternative way is to use template template parameters with variadic templates to avoid "Matching template template parameters to compatible arguments":

#include <set>
#include <vector>

template<class T, template<class, class...> class CONTAINER, class... Args>
void f(CONTAINER<T, Args...> *){}

int main(){
    std::vector<int> v;
    f(&v);
    std::set<int> s;
    f(&s);
}

or

#include <set>
#include <vector>

template<template<class, class...> class CONTAINER, class... Args>
void f(CONTAINER<int, Args...> *){}

int main(){
    std::vector<int> v;
    f(&v);
    std::set<int> s;
    f(&s);
}

This works with C++11.

Upvotes: 5

Related Questions