Type inference for templatefunctions with templated parameters

Go To StackoverFlow.com

1

What is the form (if there is one) to write template functions, where arguments are templated containers?

For example I want to write a generic sum, which will work on any container which can be iterated over. Given the code below I have to write for example sum<int>(myInts). I would prefer to just write sum(myInts) and the type to be inferred from the type which myInts contains.

/**
 @brief  Summation for iterable containers of numerical type
 @tparam cN                         Numerical type (that can be summed)
 @param[in]  container              container containing the values, e.g. a vector of doubles
 @param[out] total                  The sum (i.e. total)
 */
template<typename N, typename cN>
N sum(cN container) {
    N total;
    for (N& value : container) {
        total += value;
    }
    return total;
}
2012-04-04 16:44
by zenna
You know there's std::accumulate for that - jrok 2012-04-04 16:47


0

This, even if cumbersome, can do the trick in C++11:

template <typename C>
auto sum( C const & container ) 
     -> std::decay<decltype( *std::begin(container) )>::type

Another option is just using the same structure that accumulate does: have the caller pass an extra argument with the initial value and use that to control the result of the expression:

template<typename N, typename cN>
N sum(cN container, N initial_value = N() )

(By providing a default value, the user can decide to call it with a value or else provide the template argument --but this requires the type N to be default constructible)

2012-04-04 16:53
by David Rodríguez - dribeas
What is the arrow here? Is it the same arrow used in lambda notation - zenna 2012-04-04 17:11
@zenna: It is the syntax to provide the trailing return type, and yes, it serves the same purpose as in a lambda: [](int x) -> double { return 3*x; }David Rodríguez - dribeas 2012-04-04 17:27
For some reason it decltype( *std::begin(container) ) is a reference (I assume to ints) - zenna 2012-04-04 17:49
@zenna: You are right, the expression yields an lvalue-reference, it can be converted to the exact type in one of multiple ways, on the long path, removing the reference and then the const-volatile qualification, or using decay that will do both at once - David Rodríguez - dribeas 2012-04-04 18:05


3

I write such a function like this

template<typename IT1>
typename std::iterator_traits<IT1>::value_type //or decltype!
function(IT1 first, const IT1 last)
{
    while(first != last)
    {
        //your stuff here auto and decltype is your friend.
        ++first;
    }
    return //whatever
}

This way it will work with more than just containers, for example ostream iterators and directory iterators.

Call like

function(std::begin(container), std::end(container));
2012-04-04 16:49
by 111111
Ads