gowrath
gowrath

Reputation: 3224

Using default template argument

This question is best asked by example. Say I want to declare a std::priority_queue with a comparator function. I could do:

auto cmp_fn = [](const std::string& left, const std::string& right) {
    return right < left;
};

std::priority_queue<std::string, std::vector<std::string>, decltype(cmp_fn)> queue(cmp_fn);

Is there any way to avoid specifying the middle template parameter so that the default is used? Something like

auto cmp_fn = [](const std::string& left, const std::string& right) {
    return right < left;
};

std::priority_queue<std::string, /* use default */, decltype(cmp_fn)> queue(cmp_fn);

Note: This is a simplified example of something more complicated I'm doing. Please don't answer with suggestion of the form: "just use std::greater". My question is about the template arguments.

Upvotes: 2

Views: 199

Answers (2)

max66
max66

Reputation: 66200

If you're interested in a specific solution for the second template parameter of std::priority_queue, I suppose you can use the typename std::priority_queue<T>::container_type in some way (see, by example, the solution from nwp; +1).

If your interested in a more general solution (non only for the second default template type, non only for std::priority_queue), I suppose you can first develop a type trait type_n to estract the n-th type from a list

template <std::size_t N, typename T0, typename ... Ts>
struct type_n
 { using type = typename type_n<N-1U, Ts...>::type; };

template <typename T0, typename ... Ts>
struct type_n<0U, T0, Ts...>
 { using type = T0; };

next a type traits type_cnt_n (that use type_n) to extract the n-th type argument of a template-template parameter

template <std::size_t, typename>
struct type_cnt_n;

template <std::size_t N, template <typename ...> class Cnt, typename ... Ts>
struct type_cnt_n<N, Cnt<Ts...>>
 { using type = typename type_n<N, Ts...>::type; };

and last (following the answer from nwp) a make_priority_queue() function

template <typename T, typename Cmp>
auto make_priority_queue (Cmp const & cmp)
 { return std::priority_queue<T,
      typename type_cnt_n<1U, std::priority_queue<T>>::type, Cmp> { cmp }; }

The problem of this solution is that works only with template-template types with type-only template parameter (so works with std::priority_queue, with std::vector, with std::map but doesn't work with std::array).

The following is a full working ... well, a full compiling... example

#include <queue>
#include <iostream>

template <std::size_t N, typename T0, typename ... Ts>
struct type_n
 { using type = typename type_n<N-1U, Ts...>::type; };

template <typename T0, typename ... Ts>
struct type_n<0U, T0, Ts...>
 { using type = T0; };

template <std::size_t, typename>
struct type_cnt_n;

template <std::size_t N, template <typename ...> class Cnt, typename ... Ts>
struct type_cnt_n<N, Cnt<Ts...>>
 { using type = typename type_n<N, Ts...>::type; };


template <typename T, typename Cmp>
auto make_priority_queue (Cmp const & cmp)
 { return std::priority_queue<T,
      typename type_cnt_n<1U, std::priority_queue<T>>::type, Cmp> { cmp }; }

int main()
 {
   auto cmpFn = [](std::string const & l, std::string const &r)
    { return r < l; };

   auto pq = make_priority_queue<std::string>(cmpFn);
 }

Upvotes: 1

nwp
nwp

Reputation: 9991

You can use this:

template <class T, class Comparator>
using dcpq = /*default container priority queue*/
    std::priority_queue<T, typename std::priority_queue<T>::container_type, Comparator>;

to be used like

int main() {
    auto cmp_fn = [](const std::string &left, const std::string &right)
                    { return right < left; };
    dcpq<std::string, decltype(cmp_fn)> queue(cmp_fn);
}

although directly writing

std::priority_queue<std::string, typename std::priority_queue<T>::container,
    decltype(cmp_fn)> queue(cmp_fn);

might be easier.

Upvotes: 3

Related Questions