Reputation: 463
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
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{});
__
) since these names are reserved for the compiler.#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
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
...
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.
The non-deduced contexts are:
(5.1) — The nested-name-specifier of a type that was specified using a qualified-id.
Upvotes: 2