使用语言特性(不是预处理器指令)在 C++ 中自动生成大括号括起来的初始化列表
Automatic generation of a brace-enclosed initializer list in C++ using language features (NOT pre-processor directives)
我正在寻找一种仅使用本机 C++ 语言功能(最高 C++17)来完成以下任务的解决方案:
std::array<Type, unsigned int Elem> array_{Type(), // 1 - Call constructor on Type()
Type(), // 2 - ...
... , // 3 - ...
Type()} // Elems - Call the Elem:th Type() constructor
此外,我还希望每个构造函数调用都能够接受任意数量的参数。
一个具体的例子是自动编写以下内容:
std::array<std::shared_ptr<int>, 4> array_{std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>()}
也就是说,如果我知道 Type 和 Elem,我想自动化创建大括号括起来的初始化列表的过程,并在这个过程中调用 Type:s 构造函数。
有什么想法吗?
更新,我要解决的真实问题如下:
template <typename Type, unsigned int Size>
class Storage {
public:
Storage(std::initializer_list<Type> initializer) : array_{initializer} {}
private:
std::array<Type, Size> array_;
};
void foo(){
Storage<std::shared_ptr<int>, 100> storage(...);
// or perhaps
auto storage = std::make_shared<Storage<std::shared_ptr<int>, 100>>(here be an initializer list containing calls to 100 std::make_shared<int>());
}
像这样:
#include <array>
#include <memory>
#include <utility>
template <std::size_t ...I>
std::array<std::shared_ptr<int>, sizeof...(I)> foo(std::index_sequence<I...>)
{
return {(void(I), std::make_shared<int>())...};
}
std::array<std::shared_ptr<int>, 4> array_ = foo(std::make_index_sequence<4>());
来自 C++17 的保证复制省略确保数组在适当的位置构造,并且不会发生额外的移动。
return 语句扩展为 {(void(0), std::make_shared<int>()), (void(1), std::make_shared<int>())...}
。 void(...)
并非绝对必要,但 Clang 会发出警告。
但如果这是我的代码,我会改为编写一个更通用的帮助程序:
#include <utility>
template <typename R, typename N, typename F, N ...I>
[[nodiscard]] R GenerateForEach(std::integer_sequence<N, I...>, F &&func)
{
return {(void(I), func(std::integral_constant<N, I>{}))...};
}
template <typename R, auto N, typename F>
[[nodiscard]] R Generate(F &&func)
{
return (GenerateForEach<R, decltype(N)>)(std::make_integer_sequence<decltype(N), N>{}, std::forward<F>(func));
}
然后:
auto array_ = Generate<std::array<std::shared_ptr<int>, 4>, 4>([](auto){return std::make_shared<int>();});
虽然在这种情况下 lambda 会丢弃索引,但它通常最终还是有用的,特别是考虑到在 [](auto index){...}
中,index.value
是 constexpr。
我正在寻找一种仅使用本机 C++ 语言功能(最高 C++17)来完成以下任务的解决方案:
std::array<Type, unsigned int Elem> array_{Type(), // 1 - Call constructor on Type()
Type(), // 2 - ...
... , // 3 - ...
Type()} // Elems - Call the Elem:th Type() constructor
此外,我还希望每个构造函数调用都能够接受任意数量的参数。
一个具体的例子是自动编写以下内容:
std::array<std::shared_ptr<int>, 4> array_{std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>()}
也就是说,如果我知道 Type 和 Elem,我想自动化创建大括号括起来的初始化列表的过程,并在这个过程中调用 Type:s 构造函数。
有什么想法吗?
更新,我要解决的真实问题如下:
template <typename Type, unsigned int Size>
class Storage {
public:
Storage(std::initializer_list<Type> initializer) : array_{initializer} {}
private:
std::array<Type, Size> array_;
};
void foo(){
Storage<std::shared_ptr<int>, 100> storage(...);
// or perhaps
auto storage = std::make_shared<Storage<std::shared_ptr<int>, 100>>(here be an initializer list containing calls to 100 std::make_shared<int>());
}
像这样:
#include <array>
#include <memory>
#include <utility>
template <std::size_t ...I>
std::array<std::shared_ptr<int>, sizeof...(I)> foo(std::index_sequence<I...>)
{
return {(void(I), std::make_shared<int>())...};
}
std::array<std::shared_ptr<int>, 4> array_ = foo(std::make_index_sequence<4>());
来自 C++17 的保证复制省略确保数组在适当的位置构造,并且不会发生额外的移动。
return 语句扩展为 {(void(0), std::make_shared<int>()), (void(1), std::make_shared<int>())...}
。 void(...)
并非绝对必要,但 Clang 会发出警告。
但如果这是我的代码,我会改为编写一个更通用的帮助程序:
#include <utility>
template <typename R, typename N, typename F, N ...I>
[[nodiscard]] R GenerateForEach(std::integer_sequence<N, I...>, F &&func)
{
return {(void(I), func(std::integral_constant<N, I>{}))...};
}
template <typename R, auto N, typename F>
[[nodiscard]] R Generate(F &&func)
{
return (GenerateForEach<R, decltype(N)>)(std::make_integer_sequence<decltype(N), N>{}, std::forward<F>(func));
}
然后:
auto array_ = Generate<std::array<std::shared_ptr<int>, 4>, 4>([](auto){return std::make_shared<int>();});
虽然在这种情况下 lambda 会丢弃索引,但它通常最终还是有用的,特别是考虑到在 [](auto index){...}
中,index.value
是 constexpr。