[英]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.