Stephen.W
Stephen.W

Reputation: 2127

C++ - Can I make unspecified templated type (a.k.a higher-order type) as template argument?

For example, let's imagine that we need to write a function that allows user to fetch data from a remote server, and it will return a container that holds all data it fetched. For simplicity, let's consider it is synchronized, thus doesn't have any co_await, co_yield fancy staffs.

I hope the user can choses which container the function uses. For example, the function can use a std::vector, a std::list, or even a container writen by the user to store data.

Quickly I realized the function probably can be implemented by C++ templates, but soon I found out the templated type should be a unspecified type rather than a ordinary type, that is, the user should write fetchFromServer<std::list>, instead of fetchFromServer<std::list<Data>>. I
tried writing following snippets but it doesn't compile successfully. Did I write it in awrong way, or it is just impossible to use unspecified templated type in C++.

here is the snippet I wrote:

template<class T>
void fetchFromServer(T<std::string> &output);

template<>
void fetchFromServer(std::list<std::string> &output)
{
    // Use a std::list to hold data.
}

template<>
void fetchFromServer(std::vector<std::string> &output)
{
    // Use a std::vector to hold data.
}

// User can specified his own version of `fetchFromServer`.

int main()
{
    std::list<std::string> lst;
    fetchFromServer<std::list>(list);
    std::vector<std::string> vctr;
    fetchFromServer<std::vector>(vctr);
}

Upvotes: 0

Views: 67

Answers (1)

user8143588
user8143588

Reputation:

It is sort of tricky because of the parameters. But you can do this:

#include <vector>
#include <list>
#include <string>

template< template <typename T, typename... > class C, typename... Args >
void fetchFromServer(C<std::string,Args... > &output);

template<>
void fetchFromServer(std::list<std::string> &output)
{
    // Use a std::list to hold data.
}

template<>
void fetchFromServer(std::vector<std::string> &output)
{
    // Use a std::vector to hold data.
}

// User can specified his own version of `fetchFromServer`.

int main()
{
    std::list<std::string> lst;
    fetchFromServer<std::list>(lst);
    std::vector<std::string> vctr;
    fetchFromServer<std::vector>(vctr);
}

Code: https://godbolt.org/z/TanW9KjPf

In fact, you don't need the two specializations at all. You can do this:


template< template <typename T, typename... > class C, typename... Args >
void fetchFromServer(C<std::string,Args... > &output) {
    output.push_back( "1" );
    output.push_back( "2" );
    output.push_back( "3" );
}

int main()
{
    std::list<std::string> lst;
    fetchFromServer(lst);
    std::vector<std::string> vctr;
    fetchFromServer(vctr);
}

Code: https://godbolt.org/z/KMGGvW8b1

Upvotes: 2

Related Questions