How to specialize in std :: begin?

I am trying to specialize std::begin for a custom container. I do this because I want to use a range-based for with a container. This is what I have:

 class stackiterator { … }; class stack { … }; #include <iterator> template <> stackiterator std::begin(stack& S) { return S.GetBottom(); } 

I get the following error when defining my begin specialization:

No functional template matches the function of the 'begin' specialization template

What am I doing wrong?

+7
c ++ c ++ 11 templates template-specialization template-function
source share
3 answers

I am trying to specialize std::begin for a custom container. I am because I want to use a range-based for with a container.

You bark the wrong tree. Based on the for range, std::begin is not used at all. For class types, the compiler looks directly at begin and end members, and if they are not found, ADL searches for free begin and end in the associated namespaces. Normal unskilled searches are not performed; there is no way for std::begin be raised unless your class is in the std .

Even if the specialization that you want to do is possible (this will not happen if you do not represent the begin() member - an explicit specialization for the function template cannot change the type of the return value, and the overload problem returns "anything" the begin() member returns "and if you enter the begin() member, why do you specialize in std::begin to do what he would do anyway?), you still cannot use it with a range based on for .

+12
source share

The right way to add a free begin function that allows for(:) loops to add the begin(stack&) and begin(stack const&) functions to the stack namespace, which returns an iterator and const_iterator respectively (and the same for end )

Another way is to add the begin() and end() element to the stack .

The std::begin specialization is bad practice for a number of reasons, not least because of which not all for(:) loops will work with it (search rules, where they are changed in the resolution of this defect report ). Overloading std::begin is undefined behavior (you cannot overload functions in namespace std according to the standard: this makes your program poorly formed).

Here's how it should be done, even if it violates your project’s naming convention.

+2
source share

Leaving aside policy and semantic issues about whether to specialize a function template from the std ,

The following snippet does not work:

 class stackiterator {}; struct stack { stackiterator Begin() { return stackiterator{};} }; #include <iterator> namespace std { template <> stackiterator begin<stack>(stack& S) { return S.Begin(); } } 

However, the following snippet works fine:

 class stackiterator {}; struct stack { stackiterator Begin() { return stackiterator{};} }; #include <iterator> namespace std { template <> stackiterator begin<stack>(stack& S) { return S.Begin(); } } 

The key difference is the presence of Begin() vs Begin() as a member function from stack . std::begin() is defined as:

 template <class C> auto begin(C& c) -> decltype(c.begin()); template <class C> auto begin(const C& c) -> decltype(c.begin()); 

When you specialize in a function template, you should still keep the return type the same. Unless you have Begin() as a member of the stack , the compiler does not know how to determine the return type.

This is the reason for the error generated by the compiler.

By the way, there is another SO post that partially responds to what can be specialized and what cannot be specialized.

Looking at the part of the standard that deals with std::begin() , section 24.3, I see nothing about not specializing in std::begin() .

+2
source share

All Articles