简体   繁体   English

运算符 == std::variant 和 std::shared_ptr 之间的特性?

[英]operator== idiosyncrasies between std::variant and std::shared_ptr?

The automatically instantiated operator== for my std::variant<> interferes with one of its variations, which is a std::shared_ptr<> .我的std::variant<>的自动实例化operator==会干扰其变体之一,即std::shared_ptr<> My actual variant has about 12 different possible alternatives, but to keep it short, here I just show a trivial example:我的实际变体有大约 12 种不同的可能替代方案,但为了简短起见,这里我只展示一个简单的示例:

#include <iostream>
#include <string>
#include <vector>
#include <variant>
#include <memory>

using VecInt = std::vector<int>;
using VecStr = std::vector<std::string>;
using VarFoo = std::variant<std::monostate,int>;
using VarBar = std::variant<std::monostate,VecStr,VecInt>;
using PtrInt = std::shared_ptr<int>;
using VarBaz = std::variant<std::monostate,PtrInt>;
int main()
{
    VecInt v1{1,2,3};
    VecInt v2{1,2,3};
    std::cout << "v1 == v2 ? " << std::boolalpha << (v1 == v2) << std::endl;
    VecStr v3{"Hello","World"};
    VecStr v4{"Hello","World"};
    std::cout << "v3 == v4 ? " << std::boolalpha << (v3 == v4) << std::endl;
    VarFoo foo1{42};
    VarFoo foo2{42};
    std::cout << "foo1 == foo2 ? " << std::boolalpha << (foo1 == foo2) << std::endl;
    VarBar bar1{VecInt{42,43}};
    VarBar bar2{VecInt{42,43}};
    std::cout << "bar1 == bar2 ? " << std::boolalpha << (bar1 == bar2) << std::endl;
    VarBaz baz1{std::make_shared<int>(42)};
    VarBaz baz2{std::make_shared<int>(42)};
    std::cout << "baz1 == baz2 ? " << std::boolalpha << (baz1 == baz2) << std::endl;
    
   return 0;
}

Which produces the output:产生output:

v1 == v2? v1 == v2? true真的
v3 == v4? v3 == v4? true真的
foo1 == foo2? foo1 == foo2? true真的
bar1 == bar2?酒吧 1 == 酒吧 2? true真的
baz1 == baz2? baz1 == baz2? false错误的

The problem being, that the semantics of std::shared_ptr<> is to simply compare the pointer, but not go beyond that to compare the values pointed to, while the rest ( std::vector<>, std::variant<>,... ) actually compare values.问题是, std::shared_ptr<>的语义是简单地比较指针,而不是 go 之外的比较指向的值,而 rest ( std::vector<>, std::variant<>,... ) 实际上比较值。

Of course, if you just use a single pointer, it might be reasonable to assume, that operator==() should only compare the pointer values.当然,如果您只使用单个指针,则可以合理地假设operator==()应该只比较指针值。 But in the context of a variant, this makes no real sense.但是在变体的上下文中,这没有任何意义。

Now, with some fictive variant, containing shared pointers, one would have to write ones own override of operator==() , but with many variations in it, this becomes cumbersome quickly.现在,对于一些包含共享指针的虚构变体,必须编写自己的operator==()覆盖,但是其中有许多变体,这很快就会变得很麻烦。 The shortcut being to compare the index() of the shared pointer entries and give them special handling, while resorting for the other possibilities to the existing operator== .快捷方式是比较共享指针条目的index()并对其进行特殊处理,同时将其他可能性诉诸现有的operator== But there is the catch:但有一个问题:

// the standard, e.g. see https://en.cppreference.com/w/cpp/utility/variant/operator_cmp
template< class... Types >
constexpr bool operator==( const std::variant<Types...>& v,
                           const std::variant<Types...>& w );

The signature of a self written operator== for my variant will have the same function signature as the one automatically instantiated from the template in the standard.我的变体的自写operator==的签名将具有与从标准中的模板自动实例化的签名相同的 function 签名。 So, we either get linker errors (and factually cannot do a custom override for variants) or we have some infinite recursions in code like this:因此,我们要么得到 linker 错误(实际上无法对变体进行自定义覆盖),要么我们在这样的代码中有一些无限递归:

#include <variant>
#include <memory>
using DemoVar = std::variant<std::monostate,int,std::shared_ptr<int>>;
constexpr bool operator==(const DemoVar& v, const DemoVar& w) {
  if (v.index() == w.index()) {
    switch (v.index()) {
    case 2:
      // custom shared-pointer value comparison
      // ...
      return <whatever_it_takes>;
    default:
      return v == w; // bad idea! infinite recursion! Conundrum! No way to differ between    
                     // our custom and the automatically instantiated operator==!
    }
  }
  return false;
}

So, any idea, how to achieve a custom operator== for a variant, without having to type out all the cases?那么,有什么想法,如何为变体实现自定义 operator== ,而无需输入所有案例? Or should I better not use operator== at all and give the compare function another name entirely?还是我最好不要使用 operator== 并给比较 function 完全取另一个名字?

std::shared_ptr<T>::operator== compares the pointers. std::shared_ptr<T>::operator==比较指针。 Thats what it should do (irrespective of being in a std::variant or not).这就是它应该做的(无论是否在std::variant中)。 If you want to compare the pointees, then you do not want std::shared_ptr , at least not a naked one.如果您想比较指针,那么您不想要std::shared_ptr ,至少不是裸露的。 You can use a custom class:您可以使用自定义 class:

 struct my_shared_int {
     std::shared_ptr<int> value;
     // constructor / copy / move / assignment as desired
     bool operator==(const my_shared_int& other) {
         // compare the pointees
         // (after checking that values arent empty)
     }
 };

The generated std::variant<std::monostate,my_shared_int>::operator== will then compare the integers not the pointers.生成的std::variant<std::monostate,my_shared_int>::operator==然后将比较整数而不是指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM