为什么编译器说"candidate template ignored: couldn't infer template argument 'InputIterator'"?

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

本文关键字:template argument InputIterator infer couldn 编译器 candidate ignored 为什么      更新时间:2023-10-16

我正在学习模板并编写 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'

为什么编译器会说候选模板被忽略:无法推断模板参数"输入迭代器">

多谢!

[问题中的代码既不是最小的,也不是可重现的。

问题是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{});

这样,输入迭代器是可推导的,其有效性由默认参数测试。这仍然不会做你想要的,因为在部分代码中,__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'
}

__isInputIterator<InputIterator>::__result中的InputIterator无法推断,因为它处于不可推导的上下文中。

根据CPP工作草案(N4713(中关于"从类型推断模板参数"的部分:

17.9.2.5 从类型推导模板参数...

  1. 大多数情况下,用于组成 P 的类型、模板和非类型值参与模板参数推导。也就是说,它们可用于确定模板参数的值,如果这样确定的值与其他地方确定的值不一致,则模板参数推导失败。 但是,在某些上下文中,该值不参与类型推断,而是使用在其他地方推导或显式指定的模板参数的值。如果模板参数仅在非推导上下文中使用,并且未显式指定,则模板参数推导失败。

  2. 非推导上下文是:
    (5.1( —使用限定 id 指定的类型的嵌套名称说明符。

相关文章: