Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ template's template failed to compile

I've got this test program

#include<iostream>
#include<vector>
using namespace std;

template<template<class> class C, typename T>
void print(const C<T>& c){
    for(auto& e : c)cout<<e<<endl;
}
int main(){
    vector<int> v;
    print(v);
    return 0;
}

It fails to compile:

g++ m.cpp -std=c++11
m.cpp: In function ‘int main()’:
m.cpp:11:16: error: no matching function for call to ‘print(std::vector<int>&)’
        print(v);
                ^
m.cpp:6:6: note: candidate: template<template<class> class C, class T> void print(const C<T>&)
void print(const C<T>& c){
    ^~~~~
m.cpp:6:6: note:   template argument deduction/substitution failed:
m.cpp:11:16: note:   template parameters of a template template argument are inconsistent with other deduced template arguments
        print(v);
                ^

I changed print() signature from (const C& c) to (C& c), it still fails:

$ g++ m.cpp -std=c++11
m.cpp: In function ‘int main()’:
m.cpp:11:16: error: no matching function for call to ‘print(std::vector<int>&)’
        print(v);
                ^
m.cpp:6:6: note: candidate: template<template<class> class C, class T> void print(C<T>&)
void print(C<T>& c){
    ^~~~~
m.cpp:6:6: note:   template argument deduction/substitution failed:
m.cpp:11:16: note:   template parameters of a template template argument are inconsistent with other deduced template arguments
        print(v);
                ^

How to fix it?

like image 455
Troskyvs Avatar asked Mar 05 '23 10:03

Troskyvs


1 Answers

Your compilation problem arises because your template template parameter C doesn't match the declaration of std::vector:

template<
    class T,
    class Allocator = std::allocator<T>
> class vector;

As you can see, std::vector has two template parameters, while your C has only one. But, note as well that the second parameter (class Allocator) has a default type argument. Since C++17, this is well-formed even the way you've written it, as it was added that template template parameters matching doesn't require specifying parameters for ones with default arguments like Allocator. But not all compilers are supporting this modification to the language spec -- see here live how Clang 6.0.0 refuses to compile your original snippet with C++17 enabled. Going for older versions of C++ (or just any version to date of Clang), this snippet is probably what you were aiming for:

template<template<class, class> class C, typename T, typename A>
void print(const C<T, A>& c){
    for(auto& e : c)cout<<e<<endl;
}

As here you specify the correct template signature of the type (std::vector) you're later instantiating print() with.


This would work too, regardless of C++17:

template<template<class...> class C, typename T>
void print(const C<T>& c){
    for(auto& e : c)cout<<e<<endl;
}

That said, note that, as vector<int> is already a fully instantiated type, this simpler version works just as well in the given scope of your snippet:

template<typename T>
void print(const T& c){
    for(auto& e : c)cout<<e<<endl;
}

I changed print() signature from (const C& c) to (C& c), it still fails:

This is probably the better practice in this case, as you're not modifying c inside of print(). However, this has nothing to do with your error.

like image 180
Geezer Avatar answered Mar 16 '23 02:03

Geezer