Violet Giraffe
Violet Giraffe

Reputation: 33607

How to specify that template parameter is a class template, and infer its template type from another template parameter?

Consider a template function:

template <typename OutputContainerType, typename ContainerType>
static OutputContainerType processContainer(ContainerType c)
{
    OutputContainerType result;
    ...
    return result;
}

I can call it no problem like so:

std::vector<MyClass> v;
const auto result = processContainer<std::set<MyClass>>(v);

However, I know that the function will accept and produce different containers, but always with the same element type. So having to specify std::set<MyClass>> is redundant; I want to type processContainer<std::set>(v) and have the function infer the item type as decltype(v)::value_type. How can I do that? I've tried different things like

template <template<> class OutputContainerType, class ContainerType>
static OutputContainerType<typename ContainerType::value_type> processContainer(ContainerType c) {}

but can't get it to compile no matter what (my understanding of C++ template syntax and tricks is not very deep, as you can see).

Upvotes: 1

Views: 96

Answers (2)

Daniel Frey
Daniel Frey

Reputation: 56921

You can use

template<template<typename...> class OutputContainerType,
         typename InputContainerType>
static OutputContainerType<typename InputContainerType::value_type>
processContainer(InputContainerType c)
{
    using ValueType = typename InputContainerType::value_type;
    OutputContainerType<ValueType> result;
    //  ...
    return result;
}

You might also consider using const InputContainerType& c for the parameter to avoid copying the input container.

Upvotes: 2

Anton Savin
Anton Savin

Reputation: 41331

If you don't care about the allocator, you can just omit it:

template <template<typename...> class OutputContainerType, template<typename...> class ContainerType, typename ValueType>
static OutputContainerType<ValueType> processContainer(ContainerType<ValueType> c)
{
    OutputContainerType<ValueType> result;
    //  ...
    return result;
}

int main() {
    std::set<int> s {1, 2, 3};
    auto v = processContainer<std::vector, std::set, int>(s);
}

DEMO

Upvotes: 2

Related Questions