模板成员函数签名与非模板成员函数签名冲突

template member function signature conflicts to non-template member function signature

我最近在为学习目的实现我自己的 Vector 容器时遇到了一个问题。

在我的Vector class中声明了一个非模板成员函数和一个同名的模板成员函数(插入函数)。如果发生冲突(当某些模板特化与非模板函数签名完全匹配时),编译器会给我错误....

假设我的向量 class 有 2 个称为插入的函数:

/* Vec.h */
template <class T> class Vec {
public:
    iterator insert ( iterator position, size_type n, const value_type& val );

    template <class InputIterator>
    iterator insert (iterator position, InputIterator first, InputIterator last);
}
#include "Vec.hpp"

在Vec.hpp中:

/* Vec.hpp */
template <class T>
typename Vec<T>::iterator Vec<T>::insert( iterator position, 
                                          size_type n, 
                                          const value_type& val)
{
    /* Implementation */
}

template <class T> template <class InputIterator>
typename Vec<T>::iterator Vec<T>::insert( iterator position,
                                          InputIterator first,
                                          InputIterator last )
{
    /* Some code ... */

    /* Copy the element */
    while( first != last )
    {
        new ( position + idx ) T(*first);
        ++idx;
        ++first;
    }

    /* Some other code ... */
}

在main.cpp中:

int main()
{
    Vec<int> myVec;
    MyVec.push_back(5);
    myVec.insert( myVec.begin(), 3, 3);
}

编译器错误:

../Vec.hpp: In instantiation of ‘T* Vec<T>::insert(Vec<T>::iterator, InputIterator, InputIterator) [with InputIterator = int; T = int; 
Vec<T>::iterator = int*]’:
../main.cpp:128:45:   required from here
../Vec.hpp:306:30: error: invalid type argument of unary ‘*’ (have ‘int’) 
new ( position + idx ) T(*first);
                          ^

编译器似乎试图使用模板插入函数而不是非模板插入函数。这与我的想法是矛盾的。看起来虽然我没有提供插入函数的参数列表:

myVec.insert<int*>

编译器隐式实例化了int类型的模板插入函数。

在cppreference的member templates中,也说编译器应该在这种情况下使用非模板。(请参考成员函数模板部分)

我的环境:Ubuntu 16.04 LTS, g++ (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609

  1. 解释为什么编译器使用模板成员函数

  2. 提供上述问题的解决方案。这样当我执行 insert(iterator, int, int) 或其他类似的函数调用时,例如 insert(iterator, unsigned int/long, unsigned int/long),它会调用正确的成员函数。

感谢大家的帮助。非常感谢!!

myVec.insert( myVec.begin(), 3, 3);

首先发生的事情是找到所有可能的重载:

iterator insert ( iterator position, size_type n, const value_type& val );
template <class InputIterator>
iterator insert (iterator position, InputIterator first, InputIterator last);

然后它进行模板参数推导。在这种情况下,InputIterator=int 有效。

iterator insert ( iterator position, size_type n, const int& val );
template <>
iterator insert (iterator position, int first, int last);

因为 33 都是 int.

类型

现在可以进行 ocerload 解析。这里的模板函数转换为零。 non-template 需要将 int 转换为 size_type.

转化次数为零的获胜。如果他们 并列 ,则 non-template 函数获胜;但零转化获胜。

注意迭代器类型是int不是int*;这会导致正文无法编译,因为 int 无法取消引用。