C++ 非递归访问自定义变量-如何优雅地返回值?
我正在为一个个人项目和学习经验编写一个基本版本的C++ 非递归访问自定义变量-如何优雅地返回值?,c++,templates,variant,c++20,fold-expression,C++,Templates,Variant,C++20,Fold Expression,我正在为一个个人项目和学习经验编写一个基本版本的std::variant。我想要实现的访问策略是一个if…else if链,而不是一个constepr函数指针表。原因是后者是众所周知的编译器难以优化的,并且很容易生成一个基准,其中std::visit被一系列if…else if击败 我试图用折叠表达式来实现它,但是当找到正确的访问者时,我找不到返回值的方法。这就是我到目前为止所做的: template <typename... Ts> struct my_variant {
std::variant
。我想要实现的访问策略是一个if…else if
链,而不是一个constepr
函数指针表。原因是后者是众所周知的编译器难以优化的,并且很容易生成一个基准,其中std::visit
被一系列if…else if
击败
我试图用折叠表达式来实现它,但是当找到正确的访问者时,我找不到返回值的方法。这就是我到目前为止所做的:
template <typename... Ts>
struct my_variant
{
std::byte _buffer[std::max({sizeof(Ts)...})];
std::size_t _discriminator;
// ...
auto match(auto&&... fs)
{
overload_set matcher(std::forward<Fs>(fs)...);
[&]<std::size_t... Is>(std::index_sequence<Is...>)
{
([&]
{
if (_discriminator == Is)
{
// How to return from here?
matcher(*reinterpret_cast<Ts *>(&_buffer));
}
}(), ...);
}
(std::make_index_sequence_for<Ts...>{});
}
};
模板
结构我的变量
{
字节缓冲区[std::max({sizeof(Ts)…})];
std::大小鉴别器;
// ...
自动匹配(自动和…fs)
{
重载集匹配器(std::forward(fs)…);
[&](标准::索引_序列)
{
([&]
{
if(_鉴别器==Is)
{
//从这里怎么回来?
匹配器(*重新解释强制转换(&缓冲区));
}
}(), ...);
}
(std::为{}生成索引序列);
}
};
我目前的策略是为变量中的所有类型创建一个std::index_序列
,然后折叠逗号操作符,使编译器生成一组if
语句。因为如果
不是一个表达式,我必须将它包装成一个lambda表达式,以便能够折叠它。如果我尝试返回,我将从lambda本身返回,它不会传播到上层
我可以使用一个缓冲区来存储结果,然后返回它,但这并没有达到目的,因为它会阻止RVO
是否有一种方法可以编写
非递归匹配
并仍然返回访问者的结果,从而允许RVO发生?您需要选择一个不放弃该值的运算符
template <typename T>
struct result { // aka std::optional
std::aligned_storage_t<T> store;
bool has_value;
result() : has_value(false) {}
result(T t) : new(store) T(std::move(t)), has_value(true) {}
const result & operator| (const result & other) const { return has_value ? *this : other; }
T get() { return std::move(*reinterpret_cast<T *>(store)); }
};
template <typename... Ts>
struct my_variant
{
std::byte _buffer[std::max({sizeof(Ts)...})];
std::size_t _discriminator;
// ...
auto match(auto&&... fs)
{
overload_set matcher(std::forward<Fs>(fs)...);
using result_t = result<std::common_type_t<std::invoke_result_t<matcher, Ts>...>>;
return [&]<std::size_t... Is>(std::index_sequence<Is...>)
{
return ([&]() -> result_t
{
if (_discriminator == Is)
{
// How to return from here?
return matcher(*reinterpret_cast<Ts *>(&_buffer));
}
return result_t{};
}() | ...);
}
(std::make_index_sequence_for<Ts...>{}).get();
}
};
模板
结构结果{//aka std::可选
标准:对齐的存储存储存储;
bool具有_值;
result():具有_值(false){
结果(T):新的(存储)T(std::move(T)),具有_值(true){
const result&运算符|(const result&other)const{return具有_值?*this:other;}
T get(){return std::move(*reinterpret_cast(store));}
};
模板
结构我的变量
{
字节缓冲区[std::max({sizeof(Ts)…})];
std::大小鉴别器;
// ...
自动匹配(自动和…fs)
{
重载集匹配器(std::forward(fs)…);
使用结果\u t=结果;
返回[&](标准::索引_序列)
{
返回([&]()->结果
{
if(_鉴别器==Is)
{
//从这里怎么回来?
返回匹配器(*重新解释强制转换(&_缓冲区));
}
返回结果{};
}() | ...);
}
(std::make_index_sequence_for{}).get();
}
};
我想你应该这样做。这很聪明,但并不能真正解决最初的问题。您仍然需要一个缓冲区来存储结果,还有额外的检查和额外的move构造函数调用。