我不明白带有包扩展的 lambda std::array 的初始化

问题描述 投票:0回答:1

我发现以下代码(by phoeen)在运行时实例化基于索引的变体:

template <typename... Ts>
std::variant<Ts...> make_variant(std::size_t i)
{
    assert(i < sizeof...(Ts));
    static constexpr auto table = std::array{ +[](){ return std::variant<Ts...>{Ts{ }}; }...  };
    return table[i]();
}

它可以工作(对我来说,c++17,gcc 8.5),但是我不明白数组的实例化

table

  1. 为什么 std::array 这里没有模板类型?
  2. lambda 之前的
    +
    的目标是什么?
  3. 这个折叠表达式是如何工作的?
c++ c++17 variant fold-expression
1个回答
0
投票
  1. 为什么
    std::array
    这里没有模板类型?

C++17 添加了 类模板参数推导 (CTAD),这使得可以通过隐式指南或用户提供的推导指南从提供的参数推导类模板模板参数。对于

std::array
,有一位用户提供的推演指南:

template< class T, class... U >
array( T, U... ) -> array<T, 1 + sizeof...(U)>;

也就是说,如果您使用

std::array{1, 2, 3}
创建数组,则
T
将推导为
int
,并且
1 + sizeof...(U)
(1 + 2) 将是
std::array
的非类型大小参数,因此它变为
std::array<int, 3>

  1. lambda 之前的
    +
    的目标是什么?

每个 lambda 都成为唯一类型,但一元加号可用于非捕获 lambda 以获得指向它的常规函数指针。在这种情况下,所有 lambda 都将具有类型

std::variant<Ts...>(*)()
,即指向不带参数并返回
std::variant<Ts...>
的函数的指针。

  1. 这个折叠表达式是如何工作的?

这不是折叠表达式,而是参数扩展。 对于每个

Ts...
,创建一个lambda,返回初始化特定
std::variant<Ts...>
类型的
Ts
。示例:

auto v = make_variant<int, double>(1);

将实例化此函数:

std::variant<int, double> make_variant(std::size_t i) {
    static constexpr std::array<std::variant<int, double>(*)(), 2> table{
        +[]() { return std::variant<int, double>{int{}}; },
        +[]() { return std::variant<int, double>{double{}}; },
    };
    return table[i](); // return the variant initialized at pos `i`
}
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.