Question

My understanding is that template argument deduction is only for function templates, but function templates does not allow partial specialization. Is there a way to achieve both?

I basically want to achieve a function-like object (can be a functor) with the signature

template<class InputIterator1, class InputIterator2, class OutputIterator, int distribution>
void GetQuantity(InputIterator1 frist1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, double supply, double limit);

Depending on the value of distribution, I want to have a couple of specializations of this template. And when I call this function,I basically do not want to specify all the type parameters, because they are many of them (and thus I need argument deduction)!

Was it helpful?

Solution

You can achieve this with a functor thats templated on distribution and let the deduction be done on a call to operator():

template<int distribution>
struct GetQuantity {
    template<class InputIterator1, class InputIterator2, class OutputIterator>
    void operator()(
        InputIterator1 frist1, InputIterator1 last1, InputIterator2 first2, 
        OutputIterator result, double supply, double limit );
};

template<>
struct GetQuantity<0> {
    // specialized stuff
};

OTHER TIPS

An alternative to partially specializing a struct is to use std::integral_constant overloads:

template<class InputIterator1, class InputIterator2, class OutputIterator>
void GetQuantity(InputIterator1 first1, InputIterator1 last1,
                 InputIterator2 first2, OutputIterator result,
                 double supply, double limit,
                 std::integral_constant<int, 0>);

This can be called via a dispatcher:

template<int distribution,
         class InputIterator1, class InputIterator2, class OutputIterator>
void GetQuantity(InputIterator1 first1, InputIterator1 last1,
                 InputIterator2 first2, OutputIterator result,
                 double supply, double limit)
{
    GetQuantity(first1, last1, first2, result, supply, limit,
                std::integral_constant<int,distribution>{});
}

A default implementation can be provided via a conversion sequence:

template<int dist>
struct der_int_const : std::integral_constant<int, dist>
{}

template<int distribution,
         class InputIterator1, class InputIterator2, class OutputIterator>
void GetQuantity(InputIterator1 first1, InputIterator1 last1,
                 InputIterator2 first2, OutputIterator result,
                 double supply, double limit, der_int_const<distribution>{});

There's another way to even partially specialize even on the distribution parameter (simplified):

#include <iostream>
#include <type_traits>

struct X0{};
struct X1{};

template<int distribution, class It,
         class U = typename std::enable_if<distribution==0>::type>
void GetQuantity(It, X0={});

template<int distribution, class It,
         class U = typename std::enable_if<(distribution>1)>::type>
void GetQuantity(It, X1={});

C++03 version:

#include <boost/type_traits.hpp>

and then use boost::integral_constant instead of std::integral_constant

#include <boost/utility/enable_if.hpp>

struct X0{};
struct X1{};

template<int distribution, class It>
typename boost::enable_if_c<distribution==0>::type
GetQuantity(It, X0=X0()){ std::cout<<"0\n"; }

template<int distribution, class It>
typename boost::enable_if_c<(distribution>1)>::type
GetQuantity(It, X1=X1()){ std::cout<<"1\n"; }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top