迭代器构造函数的推导模板参数

Deducting template parameter for iterator constructor

提问人:Emile Papillon-Corbeil 提问时间:11/6/2023 最后编辑:Nicol BolasEmile Papillon-Corbeil 更新时间:11/6/2023 访问量:51

问:

我正在尝试为我的类创建一个构造函数,该构造函数将容器的迭代器作为参数并创建另一种类型的容器(假设类似于数组中的跨度)。

我想使用模板推导指南来支持这一点,并且我成功地使用了非 cv 合格的迭代器,但是当我通过常量迭代器时,它未能扣除:

// Deduction guide
<template typename Iterator>
Foo(Iterator begin, Iterator end) -> Foo<typename std::iterator_traits<Iterator>::value_type>;
std::vector<int> v{1, 2, 3, 4, 5}; 
Foo foo(v.begin(), v.end());
Foo otherFoo(v.cbegin(), v.cend());  // fails deduction

经过一些反复试验,我能够让它与这个推论指南一起工作:

template <class Iterator>
Foo(Iterator begin, Iterator end) -> Foo<std::conditional_t<std::is_const_v<typename std::iterator_traits<Iterator>::value_type>,
                             typename std::iterator_traits<Iterator>::value_type,
                             typename std::iterator_traits<Iterator>::value_type const>>;

但是当我使用 C++20 进行编译时,我不明白为什么会这样。从 cpp 首选项中,应剥离 cv-qualification。std::iterator_traits::value_type

作为测试,使用相同的环境,我进行了以下测试:

// test with non-const iterator
if (std::is_const_v<std::iterator_traits<decltype(v.begin())>::value_type>)
{
    std::cout << "it is const" << std::endl;
} else 
{
    std::cout << "It is not const" << std::endl;
}

// test with const iterator
if (std::is_const_v<std::iterator_traits<decltype(v.cbegin())>::value_type>)
{
    std::cout << "it is const" << std::endl;
} else 
{
    std::cout << "It is not const" << std::endl;
}

并得到了预期:两者都在打印“它不是常量”。那么,为什么上面的模板指南会起作用呢?

Godbolt 链接

示例类

template <class T>
class Foo{
  public:
    template <class Iterator>
    Foo(Iterator begin, Iterator end)
    : mData(&*begin) 
    , mSize(std::distance(begin, end)) {}

    T operator[](std::size_t i) {
        return *(mData+i); 
    }  
  private:
    T *mData; 
    std::size_t mSize;
}; 

// Template deduction guides
template <class Iterator>
Foo(Iterator begin, Iterator end) -> Foo<std::conditional_t<std::is_const_v<typename std::iterator_traits<Iterator>::value_type>,
                             typename std::iterator_traits<Iterator>::value_type,
                             typename std::iterator_traits<Iterator>::value_type const>>;

C++ 模板 C++20 元编程

评论

0赞 VainMan 11/6/2023
那么,为什么上面的模板指南会起作用呢?因为您正在对 BOTH 和 case 使用 (false 分支)。T = value_type constconditional_tbegin()cbegin()

答:

0赞 康桓瑋 11/6/2023 #1

那么,为什么上面的模板指南会起作用呢?

由于始终是 cv-unqualified,因此这总是假的,因此您的约简指南等效于value_typestd::conditional_t

template <class Iterator>
Foo(Iterator begin, Iterator end) -> 
  Foo<typename std::iterator_traits<Iterator>::value_type const>;

这意味着实际上推导出 是 而不是 .Foo(v.begin(), v.end())Foo<const int>Foo<int>

C++20 中的适当定义是

template <class Iterator>
Foo(Iterator begin, Iterator end) -> 
  Foo<std::remove_reference_t<std::iter_reference_t<Iterator>>>;