Reputation: 2063
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
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);
Upvotes: 3
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