如何在继承可变参数模板类型列表的类方法中调用成员类方法?
问题
我希望实现一个类,能够让一系列类按顺序调用各自的decode/encode方法,为此编写了如下模板类代码:
/// This class manages the decoding/encoding of a sequence of binary fields. template <typename Derived, typename... Fields > struct BinarySequence : Fields... { using Super = BinarySequence; bool decode(const char* buffer, size_t& length) { return true && Fields...::decode(buffer, length); } bool encode(char* buffer, size_t& length) { return true && Fields...::encode(buffer, length); } };
但Fields...::decode(buffer, length)的调用方式不正确。例如当我使用BinarySequence< MessageType, MessageSender, MessageTimeStamp >时,希望decode方法能实现如下逻辑:
bool decode(const char* buffer, size_t& length) { return MessageType::decode(buffer, length) && MessageSender::decode(buffer, length) && MessageTimeStamp::decode(buffer, length); }
请问正确的实现方式是什么?我使用的是Visual Studio 2017。
解决方案
方式1:C++17折叠表达式(VS2017 15.5及以上版本支持)
原代码的问题在于折叠表达式的语法错误,正确的&&折叠表达式需要用括号包裹以明确展开规则。修改后的代码如下:
/// This class manages the decoding/encoding of a sequence of binary fields. template <typename Derived, typename... Fields > struct BinarySequence : Fields... { using Super = BinarySequence; bool decode(const char* buffer, size_t& length) { // 按模板参数顺序依次调用每个Field的decode,保留&&的短路求值特性 return (true && ... && Fields::decode(buffer, length)); } bool encode(char* buffer, size_t& length) { return (true && ... && Fields::encode(buffer, length)); } };
编译器会将(true && ... && Fields::decode(...))展开为你期望的链式&&调用,并且只要有一个decode返回false,后续调用会被短路跳过。
方式2:初始化列表兼容写法(适配VS2017早期版本)
如果你的VS2017版本较早,对折叠表达式支持不完善,可以使用初始化列表的方式强制按顺序调用:
template <typename Derived, typename... Fields > struct BinarySequence : Fields... { using Super = BinarySequence; bool decode(const char* buffer, size_t& length) { bool result = true; // 利用初始化列表的顺序求值特性,依次执行每个Field的decode auto dummy = { (result = result && Fields::decode(buffer, length), 0)... }; (void)dummy; // 消除未使用变量的编译警告 return result; } bool encode(char* buffer, size_t& length) { bool result = true; auto dummy = { (result = result && Fields::encode(buffer, length), 0)... }; (void)dummy; return result; } };
这种写法基于C++11的初始化列表特性,VS2017完全支持。初始化列表会严格按照模板参数顺序执行每个元素的表达式,同时借助&&的短路特性,当result变为false时,后续的decode/encode调用会被跳过。
内容的提问来源于stack exchange,提问作者hlide
相关产品推荐
相关产品推荐

