неоднозначность разрешения перегрузки конструктора шаблона класса - PullRequest
1 голос
/ 31 октября 2019

Я пишу шаблон класса, такой как 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)

выдаст мне ошибку, онпохоже, что программа использует второй конструктор вместо первого. кто-нибудь может объяснить почему? вектор stl говорит

Эта перегрузка участвует только в разрешении перегрузки, если InputIt удовлетворяет LegacyInputIterator, чтобы избежать неоднозначности с перегрузкой (3).

, так как я могу изменить свойкод, чтобы избежать этого? заранее спасибо.

1 Ответ

1 голос
/ 31 октября 2019

Вторая перегрузка выбрана потому, что она лучше соответствует типам аргументов, когда Input равно int. В частности, учитывая аргументы (int, int), перегрузка (int, int) лучше соответствует перегрузке (size_t, int const&). Обратите внимание, что если вы измените первый параметр первой перегрузки с size_t на int, он будет выбран вместо.

Если вы хотите отключить перегрузку шаблона функции, когда Input является входным итераторомВы можете использовать SFINAE , используя 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)
{
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...