Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

checking iterator type in a container template class

I am writing a container class, and want to provide a constructor taking iterators as parameter, but only if the underlying iterated type matches the container type.

So I wrote:

template<typename T>
class Buffer
{
public:
    template <typename InputIter>
    typename std::enable_if<std::is_same<typename std::iterator_traits<InputIter>::value_type, typename T>>::type
    Buffer(InputIter first, InputIter last)
    {
    }
};

But I have compilation errors saying the template argument 1 and 2 are invalid

What is wrong?

Code with compiler here : https://onlinegdb.com/SyIqN_mBG

like image 489
galinette Avatar asked Dec 10 '22 08:12

galinette


2 Answers

Almost there. What you need to remember, as you were told in comments, is that constructors don't have return types. The usual trick of SFINAE on the return type won't work on them.

But they can have additional template parameters, ones that are always defaulted anyway, but the mere existence of can be used for SFINAE. So let's use that very test you provided (after adding a missing ::value) to add a non-type template parameter to the c'tor:

template<typename T>
class Buffer
{
public:
    template <typename InputIter, 
      typename std::enable_if<std::is_same<typename std::iterator_traits<InputIter>::value_type, T>::value, int>::type = 0>
    Buffer(InputIter first, InputIter last)
    {
    }
};

So if the iterators are proper, we have an additional int = 0, and if they aren't, SFINAE! The c'tor is removed from the set of overloads.

like image 131
StoryTeller - Unslander Monica Avatar answered Jan 20 '23 09:01

StoryTeller - Unslander Monica


SFINAE has 3 usable places:

  • as return type
  • as parameter type
  • as template type

For constructor, you cannot use return type.

I suggest default template parameter:

template<typename T>
class Buffer
{
public:
    template <typename InputIter,
              typename std::enable_if<
                           std::is_same<typename std::iterator_traits<InputIter>::value_type,
                                        T>::value,
                                      bool>::type = false>
    Buffer(InputIter first, InputIter last)
    {
    }
};
like image 42
Jarod42 Avatar answered Jan 20 '23 10:01

Jarod42