【问题标题】:Why compiler said "candidate template ignored: couldn't infer template argument 'InputIterator'"?为什么编译器说“候选模板被忽略:无法推断模板参数'InputIterator'”?
【发布时间】:2023-03-06 21:27:01
【问题描述】:

我正在学习模板和写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”

非常感谢!

【问题讨论】:

    标签: c++ c++11 templates


    【解决方案1】:

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

    问题是cls&lt;T&gt;::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&lt;InputIterator&gt;::__result 总是被定义为某些东西。您想要 SFINAE 的东西,即仅当这是一个输入迭代器时才定义,否则未定义。你想要std::enable_if

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


    关于您的代码的一般 cmets:
    1. 不应使用带有双下划线 (__) 前缀的名称,因为这些名称是为编译器保留的。
    2. 代码过于复杂。查看 Stack Overflow 问题 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'
    
    }
    

    【讨论】:

      【解决方案2】:

      __isInputIterator&lt;InputIterator&gt;::__result 中的InputIterator 无法推断,因为它处于不可推断的上下文中。

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2012-09-15
        • 1970-01-01
        • 2019-12-02
        • 2020-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-09
        • 1970-01-01
        相关资源
        最近更新 更多