user664303
user664303

Reputation: 2063

How do you explicitly instantiate a function with a template template parameter

I have a C++ function of the form (it's a bit more complicated; this is the MWE):

template <typename T>
struct Meas {
   T time;
   T value;
};

template <typename T, template <typename U> class container>
      T func(typename container<Meas<T>>::const_iterator start,
             typename container<Meas<T>>::const_iterator end)
{
    T c = 0;
    while (start != end) {
       c += start->value;
    }
    return c;
}

I'm having trouble explicitly instantiating it. I've tried most permutations of:

template double func<double, X>(std::deque<Meas<double>>::const_iterator, 
                                std::deque<Meas<double>>::const_iterator);

with X being one of the following:

std::deque
template std::deque
template std::deque<double>
std::deque<double>
template <typename U> std::deque<U>
template <typename U> std::deque

but none of them compile in Xcode 9.0. The most common error is:

Explicit instantiation of 'func' does not refer to a function template, variable template, member function, member class, or static data member

How should I correctly explicitly instantiate this function?

Upvotes: 2

Views: 1939

Answers (2)

songyuanyao
songyuanyao

Reputation: 172894

There're two issues, the 1st one is that std::deque has two template parameters (the 2nd one has a default value std::allocator<T>), which doesn't match the template template parameter declaration of func. You can change template <typename U> class container to template <typename, typename> class container or use parameter pack like template <typename...> class container, which allows any number of the template parameters.

The 2nd one is that func takes parameters of type container<Meas<T>>::const_iterator, which doesn't match the type in the explicit instantiation (i.e. std::deque<double>::const_iterator).

The following should work.

template <typename T, template <typename...> class container>
      T func(typename container<Meas<T>>::const_iterator start,
             typename container<Meas<T>>::const_iterator end) 
{
    ...
}

template 
double func<double, std::deque>(std::deque<Meas<double>>::const_iterator, 
                                std::deque<Meas<double>>::const_iterator);

LIVE

Upvotes: 3

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275350

std::deque is a template<class, class>class with a defaulted 2nd parameter, not a template<class>class. So it doesn't qualify.

Sometimes template <class...> class container can fix this, with X being std::deque.


In your simplified example, the container serves no useful purpose. You just want the iterator value type. Odds are this kind of pointlessness remains in your real code, as wanting the container from which an iterator comes is not how the container/iterator design of the std library is designed. You should not care.

Use using T=typename std::iterator_traits<Iterator>::value_type; to extract T from an iterator type instead of what you are doing.

template <class It, class T=typename std::iterator_traits<It>::value_type>
T func(It start, It end)
{
  T c = 0;
  while (start != end) {
    c += start->value;
    ++start;
  }
  return c;
}

this can deduce its template arguments, like 99% of good template functions should.

Then if you need to instantiate it:

template double func<std::deque<double>::const_iterator, double>(std::deque<double>::const_iterator, 
                            std::deque<double>::const_iterator);

the ,double may not be needed, my in-head compiler is uncertain and I don't care to check it.

Upvotes: 2

Related Questions