将包装器对象用作具有可变模板和引用参数的 RValue
Using wrapper objects as RValues with variadic template and reference parameters
我有一个可变参数模板函数
template<typename ...ARGS>
inline void ReadStream::decode(ARGS&...args) {
internalDecode(args...);
}
template<typename T, typename ...ARGS>
inline void ReadStream::internalDecode(T &head, ARGS&...args) {
read(head);
internalDecode(args...);
}
inline void ReadStream::internalDecode() {
}
这让我可以写
int a, b;
ByteArray c;
String d
x.decode(a,b,c,d);
将传入的二进制流解压缩为一组没有样板的变量。
我实现了一个包装器对象 'FixedSize',它改变了特定变量 read/decoded 的默认格式。
template <typename T>
class FixedSize{
T &value;
uint16_t length;
public:
FixedSize(T &wrapped, uint32_t size):
value(wrapped),
length(static_cast<uint16_t>(size)){
}
template< typename STREAM>
void read(STREAM &stream){
stream.readBytes(value, 0, length);
value.setLength(length);
}
};
template<typename T>
FixedSize<T> fixedSizeField(T &field, uint32_t length){
return FixedSize<T>(field, length);
}
理论上这将允许像这样调用解码
x.decode(a,b,fixedSize(c,16), d);
然而,fixedSize() 返回的对象现在是一个 RValue,编译器拒绝使用
从右值初始化 'FixedSize&' 类型的非常量引用无效....
因为 RValue 持有对底层对象的引用,如果编译器允许我编译它,这段代码实际上可以工作。事实上,如果我创建一个 FixedSize 类型的对象,然后像这样将它传递给解码函数,它就可以工作。
auto e = fixedSize(c,16)
x.decode(a,b, e, d)
我将如何强制编译器在此处接受作为右值返回的包装对象?
不要;将参数转发到任何地方(通过采用 Args&&... 并通过 std::forward(args)...),除了在头部,并进行重载。观察到包装器可能是一个常量;所以你可以把它当作一个 const& 并仍然通过引用修改目标。
此外,您不需要像我看到的那样单独使用 decode() 和 internalDecode;只保留 internalDecode() 并将其命名为 decode()。
根据 Iorro 的评论,这是使用通用引用、转发和函数重载的工作代码:
template<typename T, typename ...ARGS>
inline void ReadStream::decode(T &head, ARGS&&...args) {
read(head);
decode(std::forward<ARGS>(args)...);
}
template<typename T, typename ...ARGS>
inline void ReadStream::decode(const T &head, ARGS&&...args) {
read(head);
decode(std::forward<ARGS>(args)...);
}
inline void ReadStream::decode() {
}
FixedWrapper 中的 read 函数也需要设为常量,即
template< typename STREAM>
void read(STREAM &stream) const {
stream.readBytes(value, 0, length);
value.setLength(length);
}
现在调用时
x.decode(a,b,fixedSize(c,16), d);
这是可行的,因为 Rvalue 可以传递给采用 (const T&, ...) 的重载函数,并且一切都可以编译和运行。
我有一个可变参数模板函数
template<typename ...ARGS>
inline void ReadStream::decode(ARGS&...args) {
internalDecode(args...);
}
template<typename T, typename ...ARGS>
inline void ReadStream::internalDecode(T &head, ARGS&...args) {
read(head);
internalDecode(args...);
}
inline void ReadStream::internalDecode() {
}
这让我可以写
int a, b;
ByteArray c;
String d
x.decode(a,b,c,d);
将传入的二进制流解压缩为一组没有样板的变量。
我实现了一个包装器对象 'FixedSize',它改变了特定变量 read/decoded 的默认格式。
template <typename T>
class FixedSize{
T &value;
uint16_t length;
public:
FixedSize(T &wrapped, uint32_t size):
value(wrapped),
length(static_cast<uint16_t>(size)){
}
template< typename STREAM>
void read(STREAM &stream){
stream.readBytes(value, 0, length);
value.setLength(length);
}
};
template<typename T>
FixedSize<T> fixedSizeField(T &field, uint32_t length){
return FixedSize<T>(field, length);
}
理论上这将允许像这样调用解码
x.decode(a,b,fixedSize(c,16), d);
然而,fixedSize() 返回的对象现在是一个 RValue,编译器拒绝使用
从右值初始化 'FixedSize&' 类型的非常量引用无效....
因为 RValue 持有对底层对象的引用,如果编译器允许我编译它,这段代码实际上可以工作。事实上,如果我创建一个 FixedSize 类型的对象,然后像这样将它传递给解码函数,它就可以工作。
auto e = fixedSize(c,16)
x.decode(a,b, e, d)
我将如何强制编译器在此处接受作为右值返回的包装对象?
不要;将参数转发到任何地方(通过采用 Args&&... 并通过 std::forward(args)...),除了在头部,并进行重载。观察到包装器可能是一个常量;所以你可以把它当作一个 const& 并仍然通过引用修改目标。
此外,您不需要像我看到的那样单独使用 decode() 和 internalDecode;只保留 internalDecode() 并将其命名为 decode()。
根据 Iorro 的评论,这是使用通用引用、转发和函数重载的工作代码:
template<typename T, typename ...ARGS>
inline void ReadStream::decode(T &head, ARGS&&...args) {
read(head);
decode(std::forward<ARGS>(args)...);
}
template<typename T, typename ...ARGS>
inline void ReadStream::decode(const T &head, ARGS&&...args) {
read(head);
decode(std::forward<ARGS>(args)...);
}
inline void ReadStream::decode() {
}
FixedWrapper 中的 read 函数也需要设为常量,即
template< typename STREAM>
void read(STREAM &stream) const {
stream.readBytes(value, 0, length);
value.setLength(length);
}
现在调用时
x.decode(a,b,fixedSize(c,16), d);
这是可行的,因为 Rvalue 可以传递给采用 (const T&, ...) 的重载函数,并且一切都可以编译和运行。