Home > OS >  Template resolution with template template parameter
Template resolution with template template parameter

Time:09-27

I'm trying to implement a "decoder" which can treat input data differently depending on the expected return type.

The following code seemed to work in https://cppinsights.io/:

#include <cstring>
#include <vector>

template<template <class, class> class V, typename T>
void Bar(V<T, std::allocator<T>> &v, char** c) {
    size_t s = *(size_t*)*c;
    v.resize(s);
    memcpy((char*)&v[0], *c, s * sizeof(T));
}

template<typename T>
inline void Bar(T &t, char** c) {
    t = *(T*)*c;
}

template<typename T>
T Foo(char** c) {
    T t;
    Bar<T>(t, c);
    return t;
}

char bob[] = {8,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,7,0,0,0,9,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0};
char boz[] = {5,0,0,0};

int baz = Foo<int>((char **)&boz);
std::vector<int> bub = Foo<std::vector<int>>((char **)&bob);

So I thought that the final call to Foo would use the first definition of Bar but this is not happening, if I delete the second definition of Bar, the following code does not compile:

#include <cstring>
#include <vector>

template<template <class, class> class V, typename T>
void Bar(V<T, std::allocator<T>> &v, char** c) {
    size_t s = *(size_t*)*c;
    v.resize(s);
    memcpy((char*)&v[0], *c, s * sizeof(T));
}

template<typename T>
T Foo(char** c) {
    T t;
    Bar<T>(t, c);
    return t;
}

char bob[] = {8,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,7,0,0,0,9,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0};

std::vector<int> bub = Foo<std::vector<int>>((char **)&bob);

and I get the following error message:

error: no matching function for call to 'Bar' 
template<typename T> T Foo(char** c) { T t; Bar<T>(t, c); return t; }
                                            ^~~~~~
note: in instantiation of function template specialization 'Foo<std::vector<int>>' requested here
std::vector<int> bub = Foo<std::vector<int>>((char **)&bob);
                       ^
note: candidate template ignored: invalid explicitly-specified argument for template parameter 'V'
template<template <class, class> class V, typename T> void Bar(V<T, std::allocator<T>> &v, char** c) {
                                                           ^

I can't really understand what it means, why is the compiler not using the definition with the "template template" parameter? I have similar functions for "encoding" the data and it works, what am I doing wrong?

Am I trying to solve the wrong problem? How can I "split" the decoding function depending on the expected return type, while keeping it generic (or at least have a different handling of vector vs non-vector types)? Thanks.

CodePudding user response:

You are trying to pass T, which is a concrete type, in Foo() when you write Bar<T>(...). Instead, you'd need a template<class, class> class V there, i.e., a class template with two type arguments.

CodePudding user response:

I believe the issue is inside Foo. You're calling Bar<T> which is explicitly saying use the Bar that takes a single template argument. IE, you're making sure the template template specialization never gets selected. Instead, let it auto-deduce.

This worked for me: https://godbolt.org/z/14h1fdTMT

template<typename T>
T Foo(char** c) {
    T t;
    Bar(t, c); // auto-deduce here
    return t;
}
  • Related