Jonny0201
Jonny0201

Reputation: 463

Why compiler said "candidate template ignored: couldn't infer template argument 'InputIterator'"?

I'm learning template and writing Vector, there is a constructor in Vector :

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

Template struct __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
};

Demo :

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

Why the compiler would say that candidate template ignored: couldn't infer template argument 'InputIterator'

Thanks a lot!

Upvotes: 0

Views: 2958

Answers (2)

Michael Veksler
Michael Veksler

Reputation: 8475

[The code in the question is neither minimal nor reproducible.]

The issue is that parameters of type cls<T>::type are not deducible. This is the exact pattern you have in:

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

You simply have to reformulate the constructor so that it will be deducible:

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

This way, the InputIterator is deducible, and its validity is tested by the default parameter. This still won't do what you want, since in your partial code __isInputIterator<InputIterator>::__result is always defined to something. You want something that is SFINAE, i.e. defined only if this is an input iterator and undefined otherwise. You want something like std::enable_if:

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


General comments regarding your code:

  1. You should not use names prefixed with double underscores (__) since these names are reserved for the compiler.
  2. The code is overly complicated for what it does. Look at the Stack Overflow question How to check if an arbitrary type is an iterator? for shorter ways to check if a type is an iterator.


This is code with minimum changes that works. It is ugly, and I won't recommend using it. It simply serves to fill up the gaps in the original question:

#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'

}

Upvotes: 3

P.W
P.W

Reputation: 26800

InputIterator in __isInputIterator<InputIterator>::__result could not be deduced because it is in non-deducible context.

According to the section on "Deducing template arguments from a type", from CPP working draft (N4713):

17.9.2.5 Deducing template arguments from a type
...

  1. In most cases, the types, templates, and non-type values that are used to compose P participate in template argument deduction. That is, they may be used to determine the value of a template argument, and template argument deduction fails if the value so determined is not consistent with the values determined elsewhere. In certain contexts, however, the value does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

  2. The non-deduced contexts are:
    (5.1) — The nested-name-specifier of a type that was specified using a qualified-id.

Upvotes: 2

Related Questions