【问题标题】:Common template deduction from reference and const reference引用和常量引用的通用模板推导
【发布时间】:2020-02-29 15:47:50
【问题描述】:

我编写了一个简单的范围类来查看字节的向量(集合)。

using byte_vector = std::vector<uint8_t>;

template<typename Iter>
struct byte_range {
    static_assert( sizeof( typename std::iterator_traits<Iter>::value_type )== 1);
    using type = byte_range<Iter>;
    Iter first;
    Iter last;
    Iter begin()const{ return first; }
    Iter end()const{return last;}
    byte_range()=default;
    byte_range(Iter f, Iter l): first{f}, last{l} {}
    byte_range(byte_vector&v)      :byte_range(v.begin(),v.end()){}
    byte_range(byte_vector const&v):byte_range(v.begin(),v.end()){}
};
template<typename C> byte_range(C&)       -> byte_range<typename C::iterator>;
template<typename C> byte_range(C const&) -> byte_range<typename C::const_iterator>;

它可以从传递给构造函数的向量中推断出 Iter 类型。但我找到了同时处理非常量和常量的唯一方法。我想知道是否有办法为两者编写一个模板推导线。

我想将最后两行合并为一行。但是怎么做呢?

Test code:

#include <iostream>
#include <vector>

int main()
{
    using namespace std;

    byte_vector bv {1,2,3,4,5};
    byte_range bri(begin(bv),end(bv));
    byte_range brv(bv);
    cout<<"---"<<endl;
    for(auto&br:{bri,brv}){
        for(auto&b:br)
            cout<<hex<<int(b)<<" ";
        cout<<endl;
    }

    byte_vector const bvc = {6,7,8,9,0};
    byte_range brc = bvc;
    for(auto&b:brc)
        cout<<hex<<int(b)<<" ";
    cout<<endl;
}

【问题讨论】:

    标签: c++


    【解决方案1】:

    基本上来自我对你上一个问题的回答:

    template<typename C> byte_range(C& c) -> byte_range<decltype(c.begin())>;
    

    并且构造函数可以是一个同时适用于两者的单个模板:

    template<typename C>
    byte_range(C& v)      : byte_range(v.begin(),v.end()) {}
    

    如果让byte_range的模板参数是容器类型而不是迭代器类型,也可以去掉推导引导。

    这还允许您使用不将其iterator 类型声明为成员的类范围类型。 (为了更通用,您可能想要使用std::begin/std::end,而在 C++20 中只需使用std::ranges。)

    如果您希望您的类只表示连续范围的字节类类型,那么您可能应该使用指针接口。看看 C++20 的 std::span,它的接口和实现。

    另外,static_assert( sizeof( typename std::iterator_traits&lt;Iter&gt;::value_type )== 1); 并没有真正测试您打算测试的内容。例如,所有空类的sizeof 可能等于1。您可能想测试该类型是否满足 std::byteunsigned char 或类似的。

    【讨论】:

    • 感谢您的回复和建议,非常认知。
    【解决方案2】:

    如果模板参数推导适用于引用,则保留常量。

    例如:

    template<class T>
    void foo(T&) {}
    
    const vector<int> v;
    foo(v); // T will be deduced as const vector<int>
    

    所以,你的两个演绎指南可以合并为:

    template<typename C>
    byte_range(C&) -> 
      byte_range< std::conditional_t<std::is_const_v<C>,
      typename C::const_iterator,
      typename C::iterator> >;
    

    Demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-17
      • 1970-01-01
      • 2011-06-20
      相关资源
      最近更新 更多