Почему компилятор сказал: «Шаблон кандидата проигнорирован: невозможно определить аргумент шаблона« InputIterator »»? - PullRequest
0 голосов
/ 25 сентября 2018

Я изучаю шаблон и пишу Vector, в Vector есть конструктор:

template <typename InputIterator>
Vector(typename __isInputIterator<InputIterator>::__result, typename __isInputIterator<InputIterator>::__result, const allocator &);

Структура шаблона __isInputIterator:

struct InputIterator {
    constexpr static bool isInputIterator {true};
    //...
}
template <typename, bool>
struct __InputIteratorInferringAuxiliary {
    using __type = __falseType;
};
template <typename Iterator>
struct __InputIteratorInferringAuxiliary<Iterator, true> {
    using __type = Iterator;
};
template <typename Iterator>
struct __isInputIterator {
    using __result = typename __InputIteratorInferringAuxiliary<Iterator,
                __IteratorTraits<Iterator>::iteratorTag::isInputIterator
        >::__type;
};
template <typename T>
struct __IteratorTraits<T *> {
    using sizeType = unsigned long;
    using differenceType = long;
    using valueType = T;
    using reference = valueType &;
    using constReference = const valueType &;
    using rightValueReference = valueType &&;
    using pointer = valueType *;
    using constPointer = const valueType *;
    using iteratorTag = RandomAccessIterator;//isInputIterator tag in RandomAccessIterator class is true
};

Демонстрация:

int arr[] {1, 2, 3};
Vector<int> vec(begin(arr), end(arr));//candidate template ignored: couldn't infer template argument 'InputIterator'

Почему компилятор сказал, что шаблон-кандидат проигнорирован: не удалось вывести аргумент шаблона 'InputIterator'

Большое спасибо!

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

[Код в вопросе не является ни минимальным, ни воспроизводимым.]

Проблема в том, что параметры типа cls<T>::type не выводимы.Это именно тот шаблон, который у вас есть:

template <typename InputIterator>
Vector(typename __isInputIterator<InputIterator>::__result, typename __isInputIterator<InputIterator>::__result, const allocator &);

Вы просто должны переформулировать конструктор так, чтобы он был выводимым:

template <typename InputIterator, 
         typename __isInputIterator<InputIterator>::__result* = nullptr>
Vector(InputIterator, InputIterator, const allocator & = allocator{});

Таким образом, InputIterator выводим, иего достоверность проверяется параметром по умолчанию.Это все равно не будет делать то, что вы хотите, так как в вашем частичном коде __isInputIterator<InputIterator>::__result всегда определено для чего-то.Вы хотите что-то, что является SFINAE, то есть определено, только если это входной итератор и не определено иначе.Вы хотите что-то вроде std::enable_if:

template <typename InputIterator,
        std::enable_if_t<__isInputIterator<InputIterator>::__result::value>* x = nullptr>
 Vector(InputIterator, InputIterator, const allocator & = allocator{});


Общие комментарии относительно вашего кода:
  1. Не следует использовать имена с префиксом с двойным подчеркиванием (__), так какэти имена зарезервированы для компилятора.
  2. Код слишком сложен для того, что он делает.Посмотрите на вопрос переполнения стека Как проверить, является ли произвольный тип итератором? для более коротких способов проверить, является ли тип итератором.


Это кодс минимальными изменениями, что работает. Это ужасно, и я не буду рекомендовать его использовать .Он просто служит для заполнения пробелов в исходном вопросе:
#include <memory>
#include <type_traits>
struct InputIterator {
    constexpr static bool isInputIterator {true};
    //...
};
struct __falseType 
{
    static constexpr bool value{false};
};
struct __trueType 
{
    static constexpr bool value{true};
};

template <typename, bool>
struct __InputIteratorInferringAuxiliary {
    using __type = __falseType;
};
template <typename Iterator>
struct __InputIteratorInferringAuxiliary<Iterator, true> {
    using __type = __trueType;
};

struct NotIterator {
static constexpr bool isInputIterator = false;
};
template <typename T>
struct __IteratorTraits {
    using iteratorTag = NotIterator;
};

struct RandomAccessIterator {
        static constexpr bool isInputIterator = true;

};

template <typename T>
struct __IteratorTraits<T *> {
    using sizeType = unsigned long;
    using differenceType = long;
    using valueType = T;
    using reference = valueType &;
    using constReference = const valueType &;
    using rightValueReference = valueType &&;
    using pointer = valueType *;
    using constPointer = const valueType *;
    using iteratorTag = RandomAccessIterator;//isInputIterator tag in RandomAccessIterator class is true
};

template <typename Iterator>
struct __isInputIterator {
    using __result = typename __InputIteratorInferringAuxiliary<Iterator,
                __IteratorTraits<Iterator>::iteratorTag::isInputIterator
        >::__type;
};
template <class T, class allocator=std::allocator<T>>
class Vector
{
    public:
    template <typename InputIterator,
            std::enable_if_t<__isInputIterator<InputIterator>::__result::value>* x = nullptr>
     Vector(InputIterator, InputIterator, const allocator & = allocator{});
       T* begin();
       T* end();
};
int main()
{
    int arr[] {1, 2, 3};
Vector<int> vec(std::begin(arr), std::end(arr));//candidate template ignored: couldn't infer template argument 'InputIterator'
Vector<int> vec2(1,2);//candidate template ignored: couldn't infer template argument 'InputIterator'

}
0 голосов
/ 25 сентября 2018

InputIterator в __isInputIterator<InputIterator>::__result не может быть выведено, потому что оно находится в не выводимом контексте.

В соответствии с разделом «Вывод аргументов шаблона из типа» из рабочего проекта CPP (N4713):

17.9.2.5 Вывод аргументов шаблона из типа
...

В большинстве случаев типы, шаблоны и нетиповые значения, которые используются для составления P, участвуют в выводе аргументов шаблона.То есть они могут использоваться для определения значения аргумента шаблона, и вывод аргумента шаблона завершается неудачно, если определенное таким образом значение не соответствует значениям, определенным в другом месте.Однако в определенных контекстах значение не участвует в выводе типа, а вместо этого использует значения аргументов шаблона, которые были либо выведены в другом месте, либо явно указаны. Если параметр шаблона используется только в не выведенных контекстах и ​​не указан явно, вывод аргумента шаблона завершается неудачей.

Невыбираемыми контекстами являются:
(5.1) - Спецификатор вложенного имени типа, указанного с помощью квалифицированного идентификатора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...