[C++] SFINAE

Started by
12 comments, last by loufoque 14 years, 10 months ago
I don't understand why this code doesn't compile. The error is with std::iterator_traits. Compiler says it can't find iterator_category for std::vector which is fine. Therfore the second template should be excluded from matching. Somehow, it casues an error. Any ideas? Don't write that it's not useful. I know it. I'm only testing.

#include <vector>
#include <algorithm>
#include <iterator>

template <typename Cont, typename Cont2>
typename Cont2::iterator copy(const Cont& c, Cont2& dest)
{
    //return std::copy(c.begin(), c.end(), std::back_inserter(dest));
    std::copy(c.begin(), c.end(), std::back_inserter(dest));
    return dest.end();
}

template <typename Cont, typename It>
It copy(const Cont& c, It dest, typename std::iterator_traits<It>::pointer = 0)
{
    return std::copy(c.begin(), c.end(), dest);
}

int main()
{
    std::vector<int> a, b;

    copy(a, b);
}



Comeau errors:
"stl_iterator_base.h", line 110: error: class
          "std::vector<int, std::allocator<int>>" has no member
          "iterator_category"
    typedef typename _Iterator::iterator_category iterator_category;
                                ^
          detected during instantiation of class
                    "std::iterator_traits<_Iterator> [with
                    _Iterator=std::vector<int, std::allocator<int>>]" at line
                    21 of "ComeauTest.c"

"ComeauTest.c", line 21: error: more than one instance of overloaded function "copy"
          matches the argument list, the choices that match are:
            function template "Cont2::iterator copy(const Cont &, Cont2 &)"
            function template "It copy(const Cont &, It,
                      std::iterator_traits<_ForwardIter2>::pointer)"
            The argument types that you used are: (std::vector<int, std::allocator<int>>,
                      std::vector<int, std::allocator<int>>)
      copy(a, b);
      ^
[Edited by - rozz666 on May 29, 2009 7:11:36 AM]
Advertisement
*bump*
*bump*
I get similar error messages from VC++, but I think they may be red herrings and the real culprit may be:
line 21error C2668: 'copy' : ambiguous call to overloaded function


Additionally, neither function is a viable candidate for instantiation

template <typename Cont, typename Cont2>typename Cont2::iterator copy(const Cont& c, Cont2& dest){    return std::copy(c.begin(), c.end(), std::back_inserter(dest));}

causes

error C2664: 'std::_Vector_iterator<_Ty,_Alloc>::_Vector_iterator(const std::_Vector_iterator<_Ty,_Alloc> &)' : cannot convert parameter 1 from 'std::back_insert_iterator<_Container>' to 'const std::_Vector_iterator<_Ty,_Alloc> &'

while

template <typename Cont, typename It>It copy(const Cont& c, It dest, typename std::iterator_traits<It>::pointer = 0){    return std::copy(c.begin(), c.end(), dest);}

causes

error C2039: 'iterator_category' : is not a member of 'std::vector<_Ty>'



HTH

A5
Constipation is the thief of time.Diaorrhea waits for no man.
I fixed the error. Nevertheless, the first function is a viable candidate.
The problem seems to be that you are not just checking whether It has a subtype pointer, but trying to instantiate the iterator_traits template which fails because vector doesn't have iterator_category typedef. I don't know if that should be covered by SFINAE.

A solution might be to check for a type that is typedeffed in iterator types directly, and provide a third overload for pointers.

#include <iostream>#include <vector>#include <algorithm>#include <iterator>template <typename Cont, typename Cont2>typename Cont2::iterator copy(const Cont& c, Cont2& dest){    std::cout << "Container\n";    std::copy(c.begin(), c.end(), std::back_inserter(dest));    return dest.end();}template <typename Cont, typename It>It copy(const Cont& c, It dest, typename It::iterator_category* = 0){    std::cout << "Iterator\n";    return std::copy(c.begin(), c.end(), dest);}template <typename Cont, typename Pointer>Pointer* copy(const Cont& c, Pointer* p){    std::cout << "Pointer\n";    return std::copy(c.begin(), c.end(), p);}int main(){    std::vector<int> a, b;    std::vector<int>::iterator it;    int* p;    copy(a, b);    copy(a, it);    copy(a, p);}


(Or you could just rename one of the overloads - e.g the first might be called append instead - otherwise, if you indeed wanted to copy, you could use vector assignment operator. What kind of a system would it be where you don't know whether you'll end up with an iterator or a container where it would be important for them to be callable in the same way?)
Quote:Original post by rozz666
*bump*


Please do not bump posts in this forum.


Thanks! [smile]

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Quote:Original post by ApochPiQ
Quote:Original post by rozz666
*bump*


Please do not bump posts in this forum.


Thanks! [smile]


I am not a big friend of bumping (that is, when the bump frequency is higher than 1 bump in 3 days), too, but I think I have the slight memory of another moderator "allowing" it.

Evil Steve, if you hear me, it was not by accident you? Otherwise, all my apologies :|

I fail to find the relevant post right now, though.
You may not have noticed but ApochPiQ is now the moderator for General Programming. He is now the guy who determines policy here.
@phrensel: Help Wanted allows bumping once every 24 hours. In comparison, bumping once every 1-2 hours here is entirely inappropriate. It's still in the most recent 5-10 threads at that point. The idea behind bumping is to get things visible in the forum once more, and even then, expanding on your question is almost always much preferred -- if you're bumping, presumably there's a reason people aren't answering your question, right?

This topic is closed to new replies.

Advertisement