7

I want to implement partial specializations for different container iterators. The code compiles fine if I do that for containers as such, but fails for their iterators:

Good

template<typename T>
struct IsContainer : std::false_type {};
template<typename T>
struct IsContainer<std::list<T>> : std::true_type {};
template<typename T>
struct IsContainer<std::set<T>> : std::true_type {};
template<typename T1, typename T2>
struct IsContainer<std::map<T1, T2>> : std::true_type {};

Produces error:

Class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used

for each specialization:

template<typename T>
struct IsIterator : std::false_type {};
template<typename T>
struct IsIterator<std::list<T>::iterator> : std::true_type {};
template<typename T>
struct IsIterator<std::set<T>::iterator> : std::true_type {};
template<typename T1, typename T2>
struct IsIterator<std::map<T1, T2>::iterator> : std::true_type {};

What is the correct form for iterators?

Mike Lischke
  • 48,925
  • 16
  • 119
  • 181
  • 1
    I dont think it is that easy in all generality to decide whether something is an iterator or not. Maybe you can check it if there is a specialization for `std::iterator_traits` – 463035818_is_not_an_ai Apr 09 '19 at 09:46
  • 1
    I dont completely agree with the duplicates. They answer the "why not" but the question here is rather about the "then how else?". Also the answer, while great, is only half of the answer – 463035818_is_not_an_ai Apr 09 '19 at 09:48
  • 2
    This answers the "then how?": https://stackoverflow.com/a/25292862/5470596 – YSC Apr 09 '19 at 09:54
  • Aside from the difficulty (or impossibility) of deducing the parameters: your container trait will only work for containers with the default allocator. For the iterators, why not just use iterator_traits instead of specializing for each container? – Useless Apr 09 '19 at 10:05

1 Answers1

5

The compiler message is quite descriptive here. That is the way how compiler deals with template specializations. I'll try to explain why this would be impossible to implement from the compiler's point of view.

When you have the following code:

template<typename T>
struct IsContainer : std::false_type {};
template<typename T>
struct IsContainer<std::list<T>> : std::true_type {};

when compiler needs to instantiate IsContainer<SomeType> it needs to check whether SomeType is a std::list with some template arguments or not, and this is quite doable. If yes - it uses partial specialization, if not - the generic one.

Let's try do the same for the following code:

template<typename T>
struct IsIterator : std::false_type {};
template<typename T>
struct IsIterator<typename std::list<T>::iterator> : std::true_type {};

If compiler needs to instantiate IsContainer<SomeType> it would need to check if SomeType is std::list<T>::iterator for some type T. Since list<T>::iterator is some independent type (theoretically) from list<T> the only option to do it is to enumerate all the possible types (including infinite number of template instantiations), which is obviously impossible.

Dmitry Gordon
  • 2,229
  • 12
  • 20