c++ - 表达式模板中的按引用捕获可以与类型推导共存吗?

标签 c++ templates expression-templates

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

为了避免昂贵的拷贝,表达式模板类可以通过引用捕获更大的参数。我将使用 Qt 的 QStringBuilder 作为示例。

当引用比表达式模板长时它起作用:

QString foo = QString("A") + QString("B");
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
              QStringBuilder<QConcatenable<QString>,
                             QConcatenable<QString>>

表达式模板的转换和解析发生在赋值时。临时字符串比赋值还长。

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

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

还有:

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

一种解决方案是让构建器保存对象的拷贝。由于这里的 QString 是隐式共享的,因此它们的复制很便宜,尽管仍然比持有引用更昂贵。不过,假设参数是 std::string:除非必要,否则您绝对不想复制它们。

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

注意:我不是在询问表达式模板的任何特定现有实现。我只使用 QStringBuilder 作为激励示例。这不是 Qt 问题或特征问题等。标题几乎就是问题。

最佳答案

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

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

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

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

关于c++ - 表达式模板中的按引用捕获可以与类型推导共存吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32566260/

相关文章:

c++ - 表达式模板不适用于 clang 下的原始类型重载

c++ - mingw32:所有编译的可执行文件挂起

c++ - 为什么要捕获访问冲突?

c++ - 如何将新节点插入到单链表中,我们没有指针指向它的头部?

c++ - 将Mat中的RGB图像转换为MFC中的BYTE *

javascript - 为什么监听器总是显示最后一次迭代的次数?

javascript - 你如何在angularjs中重用模板

C++ 和 CRTP 模式实现和编译器困境

c++ - 在表达式模板中嵌套子表达式