Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Substitution failure for template template argument

I want a helper function to instantiate a class for me. Currently it cannot compile in clang (though it compiles work in gcc), but I need it to work in clang as well. Currently I'm using clang version 6.0.0-1ubuntu2.

I'm not sure why it's failing, since gcc is able to detect the type. I tried doing stuff from this post and playing around with it for a while but I keep running into a wall. MCVE available, or you can try it on coliru here:

#include <vector>

using namespace std;

template <typename T, template <typename> typename Container>
struct SomeClass {
    SomeClass(const Container<T>& c) {
    }
};

template <typename T, template <typename> typename C>
inline auto make_some_class(const C<T>& container) {
    return SomeClass<T, C>(container);
}

int main() {
    vector<int> ints;

    auto stuff = make_some_class(ints);  
}

main.cpp:19:18: error: no matching function for call to 'make_some_class'

   auto stuff = make_some_class(ints);  

                ^~~~~~~~~~~~~~~

main.cpp:12:13: note: candidate template ignored: substitution failure [with T = int]: template template argument has different template parameters than its corresponding template template parameter

inline auto make_some_class(const C<T>& container) {

            ^

1 error generated.

like image 545
Water Avatar asked Dec 13 '22 12:12

Water


1 Answers

Suggestion: try with

#include <vector>

template <template <typename...> typename Container, typename ... Ts>
struct SomeClass {
    SomeClass(const Container<Ts...>& c) {
    }
};

template <template <typename...> typename C, typename ... Ts>
inline auto make_some_class(const C<Ts...>& container) {
    return SomeClass<C, Ts...>(container);
}

int main() {
    std::vector<int> ints;

    auto stuff = make_some_class(ints);  
}

I mean... I suppose the problem is that std::vector isn't a container that receive one type template parameter; it's a container that receive two type template parameter (the second one with a default type: std::allocator<T> where T is the first one).

So the suggestion is: make SomeClass more flexible and able to receive a container with an variadic list of template types of arguments

template <typename...> typename Container

and the corresponding list of template types

typename ... Ts

If you want a variadic list of arguments (Ts...) you need it in last position so you have to switch the position of Container and T (now Ts...): before Container and after the variadic list Ts...

template <template <typename...> typename Container, typename ... Ts>
struct SomeClass {
    SomeClass(const Container<Ts...>& c) {
    }
};

Not strictly required but, for uniformity, I suggest to rewrite make_some_class() in the same way (and, obviously, pass C before Ts... in the template parameters list).

template <template <typename...> typename C, typename ... Ts>
inline auto make_some_class(const C<Ts...>& container) {
    return SomeClass<C, Ts...>(container);
}
like image 84
max66 Avatar answered Dec 24 '22 02:12

max66