【问题标题】:Recursively unpacking a template pack for a parameter-less function递归解压缩模板包的无参数函数
【发布时间】:2020-04-22 16:13:03
【问题描述】:

我正在尝试使用可变参数模板类型包创建一个结构模板,它可以扣除传入的所有类型的大小之和。

您可以在下面找到一个简化的示例,在实际环境中,计算出的大小用于创建更多成员对象。

template <typename... Types>
struct OverallSize
{
    template <typename FirstType, typename... NextTypes>
    static constexpr size_t sizesum() { return sizeof (FirstType) + sizesum<NextTypes...>(); }
    template <typename LastType>
    static constexpr size_t sizesum() { return sizeof (LastType); }

    static constexpr size_t size = sizesum<Types...>();
};

// Should work e.g. like this
auto s = OverallSize<int, float, char>::size; // s will be 9 on x86-64

当涉及到参数列表时,我已经习惯了这种递归参数解包方法,并假设这与无参数函数和显式模板规范一样有效。但是使用 clang 编译时出现以下错误

Call to 'sizesum' is ambiguous
...
Candidate function [with FirstType = unsigned long, NextTypes = <>]
Candidate function [with LastType = unsigned long]

所以似乎最后一次递归迭代在这里不起作用——不知道为什么编译器不简单地选择最明显的选择:只有一种模板类型的那个——就像如果有一个传递给函数的实际模板参数。

那么,我必须做些什么才能使其编译并按预期工作?

【问题讨论】:

  • 使用折叠表达式 (c++17) 可以简化为:static constexpr size_t size = (sizeof(Types) + ...);.
  • 可惜对应项目支持的最高标准是c++14

标签: c++14 parameter-pack


【解决方案1】:

对于 C++14,您可以使用 SFINAE:

template <
    typename FirstType, 
    typename... NextTypes, 
    std::enable_if_t<sizeof...(NextTypes) >= 1>* = nullptr >
static constexpr size_t sizesum() {
    return sizeof (FirstType) + sizesum<NextTypes...>(); 
}

仅当参数包的大小 >= 1 时才会考虑此模板。

Demo

【讨论】:

  • 太棒了! SFINAE 表达式的强大功能(同时还有可怕的可读语法)让我一次又一次地感到惊讶
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-17
  • 1970-01-01
相关资源
最近更新 更多