从引用和const引用中推导常见模板

时间:2020-02-29 15:47:50

标签: c++

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

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类型。但是我发现了处理非const和const的唯一方法。我想知道是否有办法为两者编写一条模板推导行。

我想将最后两行压缩为一。但是如何?

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;
}

2 个答案:

答案 0 :(得分: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<Iter>::value_type )== 1);并没有真正测试您打算测试的内容。例如,所有空类都可能具有等于sizeof的{​​{1}}。您可能想测试类型是否满足1std::byte或类似的条件。

答案 1 :(得分:1)

如果模板参数推导可与引用一起使用,则将保留常量性。

例如:

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