我发现以下代码(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
:
+
的目标是什么?
- 为什么
这里没有模板类型?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>
。
- lambda 之前的
的目标是什么?
+
每个 lambda 都成为唯一类型,但一元加号可用于非捕获 lambda 以获得指向它的常规函数指针。在这种情况下,所有 lambda 都将具有类型
std::variant<Ts...>(*)()
,即指向不带参数并返回 std::variant<Ts...>
的函数的指针。
- 这个折叠表达式是如何工作的?
这不是折叠表达式,而是参数扩展。 对于每个
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`
}