使定制类型“可绑定” (兼容std :: tie) [英] Make custom type "tie-able" (compatible with std::tie)

查看:177
本文介绍了使定制类型“可绑定” (兼容std :: tie)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑我有一个自定义类型(我可以扩展):

Consider I have a custom type (which I can extend):

struct Foo {
    int a;
    string b;
};

如何使此对象的实例可分配给 std ::

How can I make an instance of this object assignable to a std::tie, i.e. std::tuple of references?

Foo foo = ...;

int a;
string b;

std::tie(a, b) = foo;
Failed attempts:

尝试失败

重载 tuple的赋值运算符< int&,string&> = Foo 是不可能的,因为赋值运算符是必须是左侧对象的成员的二进制运算符之一。

So I tried to solve this by implementing a suitable tuple-conversion operator. The following versions fail:

我试图通过实现一个合适的元组转换运算符来解决这个问题。以下版本失败:

  • operator tuple<int,string>() const
  • operator tuple<const int&,const string&>() const

  • 运算子元组< int,string>()const

  • operator tuple< const int&,const string&>()const

They result in an error at the assignment, telling that "operator = is not overloaded for tuple<int&,string&> = Foo". I guess this is because "conversion to any type X + deducing template parameter X for operator=" don't work together, only one of them at once.

他们导致在分配时出错,告诉 operator = 没有重载 tuple< ; int&,string&> = Foo 。我猜这是因为转换为任何类型X +推导模板参数X为operator =不能一起工作,只有一个一次。

Imperfect attempt:

不完美尝试:

因此,我试图为绑定类型实现转换运算符:

  • operator tuple<int&,string&>() const   Demo
  • operator tuple<int&,string&>()   Demo

  • operator tuple< int&,string&>()const 示范

  • operator tuple< int&,string&>()  演示

The assignment now works since types are now (after conversion) exactly the same, but this won't work for three scenarios which I'd like to support:

赋值现在可以工作,因为类型现在(转换后)完全相同,但这不适用于我想支持的三种情况:

  1. If the tie has variables of different but convertible types bound (i.e. change int a; to long long a; on the client side), it fails since the types have to fully match. This contradicts the usual use of assigning a tuple to a tuple of references which allows convertible types.(1)
  2. The conversion operator needs to return a tie which has to be given lvalue references. This won't work for temporary values or const members.(2)
  3. If the conversion operator is not const, the assignment also fails for a const Foo on the right hand side. To implement a const version of the conversion, we need to hack away const-ness of the members of the const subject. This is ugly and might be abused, resulting in undefined behavior.

  1. 如果绑定具有不同但可转换类型的变量绑定(即更改 int a; long long a; 在客户端),它失败,因为类型必须完全匹配。这与将元组分配给允许可转换类型的引用的元组的常规使用相矛盾。(1)

  2. 转换运算符需要返回一个给予左值引用。 (2)

  3. 如果转换运算符不是常数,那么赋值对于 const Foo 。要实现一个const版本的转换,我们需要破解const主体的成员的const。这是丑陋的,可能会被滥用,导致未定义的行为。

I only see an alternative in providing my own tie function + class together with my "tie-able" objects, which makes me force to duplicate the functionality of std::tie which I don't like (not that I find it difficult to do so, but it feels wrong to have to do it).

我只看到一个替代方法提供自己的 tie function + class和我的tie-able对象,这使得我强制重复 std :: tie 的功能不喜欢(不是我觉得很难做到这一点,但感觉有点不对。)

I think at the end of the day, the conclusion is that this is one drawback of a library-only tuple implementation. They're not as magic as we'd like them to be.

我想在一天结束时,结论是这是一个只有库的元组实现的一个缺点。

As it turns out, there doesn't seem to be a real solution addressing all of the above problems. A very good answer would explain why this isn't solvable. In particular, I'd like someone to shed some light on why the "failed attempts" can't possibly work.

事实证明,似乎没有一个真正的解决方案解决所有上述问题。一个很好的答案会解释为什么这是不可解决的。特别是,我想让某人阐明为什么失败的尝试不可能工作。

(1): A horrible hack is to write the conversion as a template and convert to the requested member types in the conversion operator. It's a horrible hack because I don't know where to store these converted members. In this demo I use static variables, but this is not thread-reentrant.


(1):一个可怕的黑客是将转换写为模板并转换为转换运算符中请求的成员类型。这是一个可怕的黑客,因为我不知道在哪里存储这些转换的成员。在此演示中,我使用静态变量,但这不是线程可重入的。

(2): Same hack as in (1) can be applied.


(2):可以应用与(1)中相同的黑客。

推荐答案

为什么当前尝试失败



std :: tie(a,b)产生 std :: tuple< int& amp;>
此类型与 std :: tuple 等无关。

code> std :: tuple< T ...> 有几个赋值运算符:

  • A default assignment-operator, that takes a std::tuple<T...>
  • A tuple-converting assignment-operator template with a type parameter pack U..., that takes a std::tuple<U...>
  • A pair-converting assignment-operator template with two type parameters U1, U2, that takes a std::pair<U1, U2>

  • 一个默认的赋值运算符,它需要一个 std :: tuple< T ...>

  • 具有类型参数包 U ... 的赋值运算符模板,其采用 std :: tuple < ..>

  • 具有两个类型参数 U1,U2的配对转换赋值运算符 ,需要一个 std :: pair< U1,U2>

For those three versions exist copy- and move-variants; add either a const& or a && to the types they take.

对于这三个版本,存在copy和move-variants;向他们所用的类型添加 const& &&

The assignment-operator templates have to deduce their template arguments from the function argument type (i.e. of the type of the RHS of the assignment-expression).

赋值运算符模板必须从函数参数类型(即赋值表达式的RHS类型)中推导出它们的模板参数。

Without a conversion operator in Foo, none of those assignment-operators are viable for std::tie(a,b) = foo. If you add a conversion operator to Foo, then only the default assignment-operator becomes viable: Template type deduction does not take user-defined conversions into account. That is, you cannot deduce template arguments for the assignment-operator templates from the type Foo.

Foo 中没有转换运算符,这些赋值运算符对于 std :: tie(a,b)= foo
如果添加一个转换操作符到 Foo
,那么只有默认的赋值运算符变得可行:
模板类型扣除用户定义的转化。
也就是说,您不能从类型 Foo 中推导出赋值运算符模板的模板参数。

Since only one user-defined conversion is allowed in an implicit conversion sequence, the type the conversion operator converts to must match the type of the default assignment operator exactly. That is, it must use the exact same tuple element types as the result of std::tie.

由于在隐式转换序列中只允许一个用户定义的转换,转换运算符转换的类型必须与默认赋值运算符的类型完全匹配。也就是说,它必须使用与 std :: tie 的结果完全相同的元组元素类型。

To support conversions of the element types (e.g. assignment of Foo::a to a long), the conversion operator of Foo has to be a template:

支持元素类型的转换(例如将 Foo :: a 分配给 long ), code> Foo 必须是一个模板:

struct Foo { int a; string b; template<typename T, typename U> operator std::tuple<T, U>(); };

However, the element types of std::tie are references.
Since you should not return a reference to a temporary,
the options for conversions inside the operator template are quite limited
(heap, type punning, static, thread local, etc).

这篇关于使定制类型“可绑定” (兼容std :: tie)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆