为什么编译器会说“候选模板被忽略:无法推断模板参数'InputIterator'”?

时间:2018-09-25 06:04:53

标签: c++ c++11 templates

我正在学习模板并编写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 :(得分:2)

无法推断InputIterator中的

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

根据CPP工作草案(N4713)中的“从类型推导模板参数”部分:

  

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

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

  2.   
  3. 非推论上下文为:
      (5.1)— 使用限定ID指定的类型的嵌套名称说明符。

  4.   

答案 1 :(得分:2)

[问题中的代码既不可少也不可复制。]

问题在于类型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. 代码的功能过于复杂。查看堆栈溢出问题How to check if an arbitrary type is an iterator?,了解检查类型是否为迭代器的更短方法。


这是最小更改有效的代码。 这很丑陋,我不建议您使用它。它只是用来填补原始问题中的空白:

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

}
相关问题