zenna
zenna

Reputation: 9196

Type inference for templatefunctions with templated parameters

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;
}

Upvotes: 1

Views: 194

Answers (2)

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)

Upvotes: 0

111111
111111

Reputation: 16168

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));

Upvotes: 3

Related Questions