表达式模板中的引用捕获是否可以与类型推导共存?

Rei*_*ica 8 c++ templates expression-templates

表达式模板通常用作优化技术,以避免创建临时对象.它们推迟构造完整对象,直到模板用于赋值或初始化.这适用于字符串构建器,线性代数包等.

为了避免昂贵的副本,表达式模板类可以通过引用捕获更大的参数.我将以Qt QStringBuilder为例.

当引用超过表达式模板时,它可以工作:

QString foo = QString("A") + QString("B");
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
              QStringBuilder<QConcatenable<QString>,
                             QConcatenable<QString>>
Run Code Online (Sandbox Code Playgroud)

表达式模板的转换和解析发生在赋值中.字符串临时表比作业更长.

唉,一旦推断出表达式模板类型而不是目标类型,我们就会遇到麻烦:

// WORKS
QString foo = []() -> QString { return QString("A") + QString("B"); }();
// FAILS
QString foo = []{ return QString("A") + QString("B"); }();
Run Code Online (Sandbox Code Playgroud)

并且:

auto foo = QString("A") + QString("B");
// foo holds references to strings that don't exist anymore
QString bar = foo; // oops
Run Code Online (Sandbox Code Playgroud)

一种解决方案是构建器保存对象的副本.由于QString这里的隐式共享,他们的复制很便宜,虽然比拿参考更昂贵.但是,假设参数是std::string:除非必要,否则你绝对不想复制它们.

是否有任何技术可用于检测完整的模板表达式是否未立即解析并且必须复制数据到目前为止只能引用?

注意:我不会询问表达式模板的任何特定现有实现.我只是QStringBuilder用作一个激励性的例子.这不是Qt问题,也不是特征问题等.标题就是这个问题.

小智 2

您不可能可靠地检测到对象的引用何时失效,除非该对象以某种方式给出它将失效的指示。您也无法提前检测是否为表达式对象调用任何特定函数,您只能在实际调用时检测到它已被调用。

如果您的对象确实提供了一种检测破坏的方法,例如,如果它有一些事件系统告诉您,那么您应该能够修改您的表达式对象。不只是保存对原始数据对象的引用,而是保存一个标记的联合。最初,存储指向原始数据对象的指针。当这些数据对象即将被销毁时,复制数据并更新标签。

但请记住,这并不能阻止问题以其他方式出现。例如,一个对象可能已被移走,在这种情况下,即使该对象仍然存在,仍未被破坏,它所保存的数据在任何合理的意义上都不再有意义。

最终,我认为您正在尝试使用技术手段来解决非技术问题:您已经决定(合理地,IMO)您不想在构造表达式时复制数据,甚至在数据构建时也不想复制数据对象使用 COW。您需要让用户了解该决定的后果,或者修改您的决定。