Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 非递归访问自定义变量-如何优雅地返回值?_C++_Templates_Variant_C++20_Fold Expression - Fatal编程技术网

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构造函数调用。