创建一个可选的元组
Create an optional tuple
我不明白为什么没有 optional tuple
,我的意思是,像这样; optional<int,string,char>
将组合 optional int
、optional string
和 optional char
。
你可以把它想象成一个优化的 std::tuple<boost::optional<T>...>
其中 optionals
使用的 booleans
将全部放在 structure
的末尾以便打包它,或者更好的是,将其存储在一个位集中。
这样可以大大减少结构体的内存,而且更优雅:
std::tuple<boost::optional<int>,boost::optional<string>,boost::optional<char>>
VS
optional<int,string,char>
我可以想到一种方法,使用 boost::optional
和 variadic templates
的实现,但在开始之前,我想知道这是否是个好主意,什么会是更好的实现方式,我将面临哪些困难?
编辑:
基本上我不喜欢的原因std::tuple<boost::optional<T>...>;
因为 optional<T>
是 T
和 bool
的联合:
新结构可以节省大量内存!!
使用模板别名不是一个好的选择吗?
template <typename... T> using optuple =
boost::optional<std::tuple<T...> >;
或者,如果您愿意,实际上还有其他变体;
template <typename... T> using optuple =
std::tuple<boost::optional<T>...>;
现在你可以写
optuple<std::string, double, int> x;
并获得您选择的含义。
当然,如果只填充了一个元组成员,则它已经存在:boost::variant<T...>
您可以自己实现,类似于:
/**
* Similar to `optional`, but take the bool as argument.
*/
template <typename T>
class out_optional
{
public:
out_optional() {}
out_optional(const out_optional&) = delete;
out_optional& operator =(const out_optional&) = delete;
void destruct(bool b) { if (b) { reset(b); } }
void reset(bool& b) { if (b) { reinterpret_cast<T*>(data)->~T(); b = false; } }
void reset(bool& b, const T& value) { reset(b); new (data) T{value}; b = true; }
void reset(bool& b, T&& value) { reset(b); new (data) T{value}; b = true; }
const T* get_ptr(bool b) const { return b ? reinterpret_cast<T*>(data) : nullptr; }
T* get_ptr(bool b) { return b ? reinterpret_cast<T*>(data) : nullptr; }
const T& get(bool b) const { assert(b); return *get_ptr(b); }
T& get(bool b) { assert(b); return *get_ptr(b); }
// Other stuff as swap, pseudo assignment/move, more constructors
private:
alignas(T) char data[sizeof(T)];
};
/**
* 'Tuple' of optional, packaged with bool at the end.
*/
template <typename ... Ts>
struct multi_optional
{
template <std::size_t I>
using type = typename std::tuple_element<I, std::tuple<Ts...>>::type;
static_assert(std::is_same<int, type<0>>::value, "");
public:
multi_optional() = default;
~multi_optional()
{
destruct(std::index_sequence_for<Ts...>());
}
multi_optional(const multi_optional&) = delete; // To be implemented.
multi_optional& operator =(const multi_optional&) = delete; // To be implemented.
template <std::size_t I>
const auto* get_ptr() const { return std::get<I>(data).get_ptr(flags[I]); }
template <std::size_t I>
auto* get_ptr() { return std::get<I>(data).get_ptr(flags[I]); }
template <std::size_t I>
const auto& get() const { return std::get<I>(data).get(flags[I]); }
template <std::size_t I>
auto& get() { return std::get<I>(data).get(flags[I]); }
template <std::size_t I>
void reset() { return std::get<I>(data).reset(flags[I]); }
template <std::size_t I>
void reset(const type<I>& value) { return std::get<I>(data).reset(flags[I], value); }
// Other stuff as copy/move assignment/constructor, ...
private:
template <std::size_t ... Is>
void destruct(std::index_sequence<Is...>)
{
int dummy[] = { 0, (std::get<Is>(data).destruct(flags[Is]), 0)... };
static_cast<void>(dummy);
}
private:
std::tuple<out_optional<Ts>...> data;
std::array<bool, sizeof...(Ts)> flags = {{}};
};
您想要的结构已经可以创建为 tuple<T>
的特化。引入额外的结构没有任何意义。与为了使用 EBO 而制作特殊 vector
相比,这里没有什么不同。
你想要的,现有界面已经完美覆盖。如果你想要另一个 实现 ,我猜你总是可以专门化或推出你自己的。
我不明白为什么没有 optional tuple
,我的意思是,像这样; optional<int,string,char>
将组合 optional int
、optional string
和 optional char
。
你可以把它想象成一个优化的 std::tuple<boost::optional<T>...>
其中 optionals
使用的 booleans
将全部放在 structure
的末尾以便打包它,或者更好的是,将其存储在一个位集中。
这样可以大大减少结构体的内存,而且更优雅:
std::tuple<boost::optional<int>,boost::optional<string>,boost::optional<char>>
VS
optional<int,string,char>
我可以想到一种方法,使用 boost::optional
和 variadic templates
的实现,但在开始之前,我想知道这是否是个好主意,什么会是更好的实现方式,我将面临哪些困难?
编辑:
基本上我不喜欢的原因std::tuple<boost::optional<T>...>;
因为 optional<T>
是 T
和 bool
的联合:
新结构可以节省大量内存!!
使用模板别名不是一个好的选择吗?
template <typename... T> using optuple =
boost::optional<std::tuple<T...> >;
或者,如果您愿意,实际上还有其他变体;
template <typename... T> using optuple =
std::tuple<boost::optional<T>...>;
现在你可以写
optuple<std::string, double, int> x;
并获得您选择的含义。
当然,如果只填充了一个元组成员,则它已经存在:boost::variant<T...>
您可以自己实现,类似于:
/**
* Similar to `optional`, but take the bool as argument.
*/
template <typename T>
class out_optional
{
public:
out_optional() {}
out_optional(const out_optional&) = delete;
out_optional& operator =(const out_optional&) = delete;
void destruct(bool b) { if (b) { reset(b); } }
void reset(bool& b) { if (b) { reinterpret_cast<T*>(data)->~T(); b = false; } }
void reset(bool& b, const T& value) { reset(b); new (data) T{value}; b = true; }
void reset(bool& b, T&& value) { reset(b); new (data) T{value}; b = true; }
const T* get_ptr(bool b) const { return b ? reinterpret_cast<T*>(data) : nullptr; }
T* get_ptr(bool b) { return b ? reinterpret_cast<T*>(data) : nullptr; }
const T& get(bool b) const { assert(b); return *get_ptr(b); }
T& get(bool b) { assert(b); return *get_ptr(b); }
// Other stuff as swap, pseudo assignment/move, more constructors
private:
alignas(T) char data[sizeof(T)];
};
/**
* 'Tuple' of optional, packaged with bool at the end.
*/
template <typename ... Ts>
struct multi_optional
{
template <std::size_t I>
using type = typename std::tuple_element<I, std::tuple<Ts...>>::type;
static_assert(std::is_same<int, type<0>>::value, "");
public:
multi_optional() = default;
~multi_optional()
{
destruct(std::index_sequence_for<Ts...>());
}
multi_optional(const multi_optional&) = delete; // To be implemented.
multi_optional& operator =(const multi_optional&) = delete; // To be implemented.
template <std::size_t I>
const auto* get_ptr() const { return std::get<I>(data).get_ptr(flags[I]); }
template <std::size_t I>
auto* get_ptr() { return std::get<I>(data).get_ptr(flags[I]); }
template <std::size_t I>
const auto& get() const { return std::get<I>(data).get(flags[I]); }
template <std::size_t I>
auto& get() { return std::get<I>(data).get(flags[I]); }
template <std::size_t I>
void reset() { return std::get<I>(data).reset(flags[I]); }
template <std::size_t I>
void reset(const type<I>& value) { return std::get<I>(data).reset(flags[I], value); }
// Other stuff as copy/move assignment/constructor, ...
private:
template <std::size_t ... Is>
void destruct(std::index_sequence<Is...>)
{
int dummy[] = { 0, (std::get<Is>(data).destruct(flags[Is]), 0)... };
static_cast<void>(dummy);
}
private:
std::tuple<out_optional<Ts>...> data;
std::array<bool, sizeof...(Ts)> flags = {{}};
};
您想要的结构已经可以创建为 tuple<T>
的特化。引入额外的结构没有任何意义。与为了使用 EBO 而制作特殊 vector
相比,这里没有什么不同。
你想要的,现有界面已经完美覆盖。如果你想要另一个 实现 ,我猜你总是可以专门化或推出你自己的。