class 模板构造函数重载解析歧义

class template constructor overload resolution ambiguity

我正在写一个class模板,像stl vector,两个构造函数是这样的:

template<class T>
vector<T>::vector(size_t count, const T&value) :bg(new T[count]),
ed(bg + count), cap(ed) {
    for (auto it = bg; it != ed; ++it)
        *it = value;
}//bg ed cap are all T*

template<class T>
template<class Input>
vector<T>::vector(Input first, Input second) : bg(new T[second - first]),
ed(bg + (second - first)), cap(ed) {
    memcpy(bg, (void*)first, sizeof(T)*(second - first));
}

所以如果我这样做

vector<int>v(2,0)

complier 给我错误,程序似乎使用了第二个构造函数而不是第一个。 谁能解释为什么? stl 向量表示

This overload only participates in overload resolution if InputIt satisfies LegacyInputIterator, to avoid ambiguity with the overload (3).

那么我该如何更改我的代码来避免这种情况呢?提前致谢。

选择第二个重载是因为当 Inputint 时它能更好地匹配参数类型。具体来说,给定参数 (int, int),重载 (int, int) 比重载 (size_t, int const&) 更匹配。请注意,如果您将第一个重载的第一个参数从 size_t 更改为 int,它将被选中。

如果你想在 Input 是一个输入迭代器时禁用函数模板重载,你可以利用 SFINAE using std::enable_if:

template <
    typename InputIt,
    typename = std::enable_if_t<
        std::is_base_of_v<
            std::input_iterator_tag,
            typename std::iterator_traits<InputIt>::iterator_category>>>
vector(InputIt, InputIt)
{
}

您可以选择将逻辑提取到类型特征中。

template <typename T, typename = void>
struct is_input_iterator : std::false_type
{
};

template <typename T>
struct is_input_iterator<T, std::void_t<typename std::iterator_traits<T>::iterator_category>>
: std::is_base_of<
    std::input_iterator_tag,
    typename std::iterator_traits<T>::iterator_category>
{
};

template <typename T>
constexpr bool is_input_iterator_v = is_input_iterator<T>::value;

然后函数定义变得更具可读性。

template <
    typename InputIt,
    typename = std::enable_if_t<is_input_iterator_v<InputIt>>>
vector(InputIt, InputIt)
{
}