从变量<C,B> 分配变量<A,B,C>?

Posted

技术标签:

【中文标题】从变量<C,B> 分配变量<A,B,C>?【英文标题】:Assign variant<A,B,C> from variant<C,B>? 【发布时间】:2017-06-29 04:51:20 【问题描述】:

使用= 不起作用。

我有这样的代码,但它“有点”难看。

#include <iostream>
#include <cassert>
#include <variant>
#include <string>

using namespace std;

namespace detail 
    template<typename... L, typename... R>
    void VariantAssignRec(variant<L...>* lhs, const variant<R...>&rhs, size_t rhs_idx, std::integral_constant<int, -1>) 
    

    template<typename... L, typename... R, int get_idx>
    void VariantAssignRec(variant<L...>* lhs, const variant<R...>&rhs, size_t rhs_idx, std::integral_constant<int, get_idx> = ) 
        assert(rhs_idx < std::variant_size_v< variant<R...>>);
        if (get_idx == rhs_idx) 
            cout << "assigning from idx " << get_idx << endl;
            *lhs = std::get<get_idx>(rhs);
            return;
        
        else 
            std::integral_constant<int, get_idx - 1> prev_get_idx;
            VariantAssignRec(lhs, rhs, rhs_idx, prev_get_idx);
        
    

template<typename... L, typename... R>
void VariantAssign(variant<L...>* lhs, const variant<R...>&rhs) 
    detail::VariantAssignRec(lhs, rhs, rhs.index(), std::integral_constant<int, std::variant_size_v<variant<R...>>-1>);



int main()

   std::variant<int, char, std::string> va = 'a';
   std::variant<std::string, int> vb = string("abc");
   cout << "va index is  " << va.index() << endl; 
   cout << "vb index is  " << vb.index() << endl; 
   VariantAssign(&va, vb);
   cout << "va index now should be 2, and it is  " << va.index() << endl; 
   vb = 47;
   VariantAssign(&va, vb);
   cout << "va index now should be 0, and it is  " << va.index() << endl; 

我正在使用 VS,所以没有 if constexpr,但我正在寻找通用 C++17 解决方案,无论 VC++ 是否缺乏支持。

【问题讨论】:

您的问题是什么?您是否发布了工作代码?堆栈溢出不适用于代码审查。您是否想要一个“更漂亮”的版本?如果有,你认为哪一部分不好? 如果您将您的代码与std 代码的大部分进行比较,那么它并没有那么糟糕。实现这些东西的想法是将丑陋的东西放到一个头文件中,然后你可以忘记它并编写使用它的漂亮代码。 visit([&amp;](auto &amp;&amp;v) dest = v; , source);。如果源中有没有在dest中的类型,可以使用visit([&amp;](auto &amp;&amp;v) if constexpr(is_assignable_v&lt;decltype(dest), decltype(v)&gt;) dest = v; else throw "unsupported"; , source) @JohannesSchaub-litb +1,喜欢这个解决方案。我正在为同一件事写一个更复杂的版本,并意识到你的要好得多 @JohannesSchaub-litb 为什么不将其转换为答案?已经很完整了 【参考方案1】:

只使用访问者:

std::variant<A, B, C> dst = ...;
std::variant<B, C> src = B;

std::visit([&dst](auto const& src)  dst = src; , src);

如果src 中有一个不能分配给dst 的类型,这将不会编译——这可能是期望的行为。

如果您最终半经常使用这种模式,您可以将分配器移到它自己的函数中:

template <class T>
auto assignTo(T& dst) 
    return [&dst](auto const& src)  dst = src; ;


std::visit(assignTo(dst), src);

【讨论】:

很漂亮,但为了记录,我宁愿避免在调用站点手动编写 std::visit ,因此我会将所有内容移至采用 src 和 dest 参数的函数。【参考方案2】:

您可以使用访问者:

struct overload_priority_low;
struct overload_priority_high : overload_priority_low;

template <typename V>
struct AssignTo

private:
    V& v; 

public:
    explicit AssignTo(V& v) : v(v) 

    template <typename T>
    void operator () (T&& t) const
    
        assign(std::forward<T>(t), overload_priority_high);   
    

private:

    template <typename T>
    auto assign(T&& t, overload_priority_high) const
    -> decltype(this->v = std::forward<T>(t), void())
    
        v = std::forward<T>(t);
    

    template <typename T>
    void assign(T&& t, overload_priority_low) const
    
        throw std::runtime_error("Unsupported type");
    

;

有用法:

int main() 
    std::variant<int, char> v = 0;
    std::variant<int, char, std::string> v2 = 42;

    std::visit(AssignTo(v), v2);

Demo

【讨论】:

你能解释一下重载解析吗?我不明白重载优先级低分配是如何被调用的。 overload_priority_high 的重载使用 SFINAE,因此如果分配无效(例如 std::variant&lt;int&gt; = std::string 之类的),则忽略该重载。唯一有效的重载是带有overload_priority_low 的重载。当两者都可以接受时,带有overload_priority_high 的那个是更好的匹配 doh,因为函数体......我总是想到 SFINAE 主要是函数参数......

以上是关于从变量<C,B> 分配变量<A,B,C>?的主要内容,如果未能解决你的问题,请参考以下文章

Python地址分配给变量

如何分配 值为jsp变量

深入理解PHP中赋值与引用

如何将HTML元素分配给JavaScript全局变量?

c语言中的变量的作用,如何从键盘中输入多个变量的值?

C动态内存分配