将包装器对象用作具有可变模板和引用参数的 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&, ...) 的重载函数,并且一切都可以编译和运行。