c++ - 制作自定义类型 "tie-able"(与 std::tie 兼容)

标签 c++ c++11 tuples std

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

struct Foo {
    int a;
    string b;
};

如何使该对象的实例可分配给 std::tie ,即 std::tuple引用文献?

Foo foo = ...;

int a;
string b;

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

尝试失败:

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

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

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

它们导致赋值错误,告诉“operator = 没有为 tuple<int&,string&> = Foo 重载”。我猜这是因为“转换为任何类型 X + 为 operator="推导模板参数 X 不能一起工作,一次只能其中一个。

不完美的尝试:

因此我尝试为领带的确切类型实现转换运算符:

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

分配现在有效,因为类型现在(转换后)完全相同,但这不适用于我想支持的三个场景:

  1. 如果 tie 绑定(bind)了不同但可转换类型的变量(即在客户端将 int a; 更改为 long long a;),则由于类型必须完全匹配,所以它会失败。这与将元组分配给允许可转换类型的引用元组的通常用法相矛盾。(1)
  2. 转换运算符需要返回一个必须给定左值引用的关系。这不适用于临时值或 const 成员。(2)
  3. 如果转换运算符不是 const,则 const Foo 的赋值也会失败在右手侧。要实现转换的 const 版本,我们需要去掉 const 主体成员的 const 特性。这很丑陋,可能会被滥用,从而导致未定义的行为。

我只看到提供自己的tie 的替代方法函数 + 类以及我的“可绑定(bind)”对象,这让我不得不复制 std::tie 的功能我不喜欢(不是我觉得这样做很困难,而是不得不这样做感觉不对)。

我认为归根结底,这是仅库元组实现的一个缺点。它们并不像我们希望的那样神奇。

编辑:

事实证明,似乎没有解决上述所有问题的真正解决方案。一个很好的答案可以解释为什么这无法解决。特别是,我希望有人能解释一下为什么“失败的尝试”不可能奏效。


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

<支持> (2): 可以应用与 (1) 相同的技巧。

最佳答案

为什么当前尝试失败

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

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

  • 一个默认的赋值运算符,它接受 std::tuple<T...>
  • 带有类型参数包的元组转换赋值运算符模板 U... , 这需要 std::tuple<U...>
  • 具有两个类型参数的对转换赋值运算符模板 U1, U2 , 这需要 std::pair<U1, U2>

对于这三个版本,存在复制和移动变体;添加 const&&&到他们采取的类型。

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

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

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

为了支持元素类型的转换(例如,将 Foo::a 赋值给 long ),Foo 的转换运算符必须是模板:

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

但是,std::tie 的元素类型是引用。 由于您不应该返回对临时的引用, 运算符模板内的转换选项非常有限 (堆、类型双关语、静态、线程本地等)。

关于c++ - 制作自定义类型 "tie-able"(与 std::tie 兼容),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26276943/

相关文章:

c++ - std::unique_ptr 取消引用异常未在 try-catch block 中捕获

c++ - 使用模板函数打印智能指针 vector

Python 计算,使用元组、列表。 Python 2.7

c++ - std::tie 是否允许隐式转换?

c++ - 传递具有可变维度的二维数组作为函数参数

c++ - 使用结构的二维 vector

c++ - 部分特化可变参数模板类的方法

Python:查找字典元组值的最大值

c++ - 在 Visual Studio 2008 中使用 _DEBUG 预处理器定义 - C++

C++11 纯右值 id 表达式?