模板上的begin()和end()自由函数重载

时间:2014-10-20 10:19:41

标签: templates c++11 boost c++14 non-member-functions

我有一个模板类,Iterable;我希望重载begin()end()免费函数。它将数据存储为vector unique_ptr,但为方便起见,界面使用boost::indirect_iterator

我的代码在CLang-3.5下构建并运行,但我尝试了g++-4.9但事实并非如此。但我不知道为什么? (以及哪种编译器具有正确的行为)。

template<typename T>
using SimpleVec = std::vector<T, std::allocator<T>>;

template <typename T,
          template <typename> class Container = SimpleVec,
          class String = std::string>
class Iterable
{
        template <typename friendT,
                  template <typename> class friendContainer,
                  class friendString>
        friend boost::indirect_iterator<typename friendContainer<std::unique_ptr<friendT>>::iterator>
            begin(Iterable<friendT, friendContainer, friendString>& i);

        template <typename friendT,
                  template <typename> class friendContainer,
                  class friendString>
        friend boost::indirect_iterator<typename friendContainer<std::unique_ptr<friendT>>::iterator>
            end(Iterable<friendT, friendContainer, friendString>& i);
};

免费功能:

template <typename T,
          template <typename> class Container = SimpleVec,
          class String = std::string>
boost::indirect_iterator<typename Container<std::unique_ptr<T>>::iterator>
    begin(Iterable<T, Container, String>& i)
{
    return boost::indirect_iterator<typename Container<std::unique_ptr<T>>::iterator>(begin(i._c));
}

template <typename T,
          template <typename> class Container = SimpleVec,
          class String = std::string>
boost::indirect_iterator<typename Container<std::unique_ptr<T>>::iterator>
    end(Iterable<T, Container, String>& i)
{
    return boost::indirect_iterator<typename Container<std::unique_ptr<T>>::iterator>(end(i._c));
}

g++上,错误是:

../../API/net/session/ClientSession.h:83:29: error: call of overloaded 'begin(GroupManager&)' is ambiguous
      for(auto& grp : groups())
                             ^
../../API/net/session/ClientSession.h:83:29: note: candidates are:
In file included from ../../API/net/session/../permission/full/PermissionManager.h:5:0,
                 from ../../API/net/session/Session.h:3,
                 from ../../API/net/session/ClientSession.h:2,
                 from ../../API/net/session/ClientSessionBuilder.h:2,
                 from ../client/main.cpp:2:
../../API/net/session/../permission/full/../../Iterable.h:22:4: note: boost::indirect_iterator<typename friendContainer<std::unique_ptr<friendT> >::iterator> begin(Iterable<friendT, friendContainer, friendString>&) [with friendT = Group; friendContainer = SimpleVec; friendString = std::basic_string<char>; T = Permission; Container = SimpleVec; String = std::basic_string<char>; typename friendContainer<std::unique_ptr<friendT> >::iterator = __gnu_cxx::__normal_iterator<std::unique_ptr<Group, std::default_delete<Group> >*, std::vector<std::unique_ptr<Group, std::default_delete<Group> >, std::allocator<std::unique_ptr<Group, std::default_delete<Group> > > > >]
    begin(Iterable<friendT, friendContainer, friendString>& i);
    ^
../../API/net/session/../permission/full/../../Iterable.h:142:2: note: boost::indirect_iterator<typename Container<std::unique_ptr<_Tp> >::iterator> begin(Iterable<T, Container, String>&) [with T = Group; Container = SimpleVec; String = std::basic_string<char>; typename Container<std::unique_ptr<_Tp> >::iterator = __gnu_cxx::__normal_iterator<std::unique_ptr<Group, std::default_delete<Group> >*, std::vector<std::unique_ptr<Group, std::default_delete<Group> >, std::allocator<std::unique_ptr<Group, std::default_delete<Group> > > > >]
  begin(Iterable<T, Container, String>& i)
  ^

所以看起来g++friend声明视为另一个函数?

2 个答案:

答案 0 :(得分:4)

由于@ sehe的答案和this cppreference page,我终于找到了答案(更具可读性)。

template <typename T,
          template <typename> class Container = SimpleVec,
          class String = std::string>
class Iterable
{
        friend boost::indirect_iterator<typename Container<std::unique_ptr<T>>::iterator>
            begin(Iterable& i)
        {
            return boost::indirect_iterator<typename Container<std::unique_ptr<T>>::iterator>(begin(i._c));
        }

        friend boost::indirect_iterator<typename Container<std::unique_ptr<T>>::iterator>
            end(Iterable& i)
        {
            return boost::indirect_iterator<typename Container<std::unique_ptr<T>>::iterator>(end(i._c));
        }
};

答案 1 :(得分:3)

类内友元函数充当在包含范围内声明的自由函数。

它将友元声明视为另一个函数,因为它是(事实上,另一个生成无界函数的函数模板,都与自由函数不同)。

如果模板完全相同,您将获得不同的诊断:

main.cpp:13:13: error: redefinition of 'begin'
char const* begin(X const&)   { return data; }
            ^
main.cpp:9:24: note: previous definition is here
    friend char const* begin(X const&)   { return data; }
                       ^

查看 Live On Coliru