我编写了一个简单的范围类,以查看字节的向量(集合)。
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的唯一方法。我想知道是否有办法为两者编写一条模板推导行。
我想将最后两行压缩为一。但是如何?
#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;
}
答案 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}}。您可能想测试类型是否满足1
或std::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> >;