【问题标题】:Template function that accepts temporaries by value and non-temporaries by reference?通过值接受临时对象和通过引用接受非临时对象的模板函数?
【发布时间】:2013-03-14 16:56:48
【问题描述】:

我想要

template <class T>
void foo(T &t);

也能够接受临时对象,而不会影响通过引用接受其他对象并在它们上调用非常量方法。在 C++03 中可能吗?

我意识到我可能会强制用户将其对象的所有方法声明为 const,并将所有成员声明为 mutable,然后使用 const T &amp;t 引用,但这是一个丑陋的解决方法。

【问题讨论】:

  • 假设foo 会尝试修改这些临时文件是否正确?为什么?
  • 不知何故,您的主题(带有“按值”的部分)不符合您的问题描述的其余部分......
  • 在 C++11 中,这是通用引用的用途......但这不是 C++03 中存在的功能
  • 你为什么要这个?正如大卫所提到的,C++11 必须对语言进行重大修改以支持这种情况(单个模板函数接受右值和左值并可以区分它们),所以如果你想模拟它,你将有更好的机会通过陈述您的要求得到答案。否则,您实际上是在要求在 C++03 中模拟右值引用,这是不可能的。

标签: c++ templates pass-by-reference c++03


【解决方案1】:

在 C++03 中,无法推断传递给函数的参数是左值还是右值。

我想这就是为什么你的问题标题说“Accepts temporaries by value”的原因:如果存在这样的机制,你可以创建一个函数(模板)来确定参数类型是否根据该信息,应该是T&amp;T

这正是 C++11 支持的类型推断机制所做的:

template<typename T>
void foo(T&& t);
//       ^^^
//       lvalue of type A is passed: T = A&, signature = foo(A& t)
//       rvalue of type A is passed: T = A, signature = foo(A&& t)

但如上所述,这在 C++03 中是不可能的,正是因为它缺乏确定表达式的值类别的方法。

您提到的可能性(强制所有对象具有const 成员函数)不是一种解决方法(甚至不是一个丑陋的方法):如果成员函数都是const,则意味着foo() 不需要改变其输入的状态。这反过来意味着它可能需要const&amp;,问题就解决了。

您可能打算让那些const 成员函数执行const_cast&lt;&gt; 以更改对象的状态,但是您也可以在foo() 内部执行相同的操作。这是一个坏主意的原因是,在这两种情况下,您都不能向foo() 输入类型为const-qualified 的对象,并且您可能不知道是否是这种情况。

【讨论】:

  • +1 用于解释,但我接受了适用于我的情况的不太通用的解决方案(没有传递 const 限定的对象)。
  • 我不明白&&的意思,但是随着你的解释,它突然点击了。非常感谢。
【解决方案2】:

您可以创建第二个函数,该函数接受 const 类型引用,并为非 const 类型引用制作副本。

template <class T>
void foo (T &t);

template <class T>
void foo (const T &x) {
    T copy(x);
    foo(copy);
}

可以在here找到演示。

此技术的局限性在于它无法区分临时对象和真正的const 对象。这样做的结果是您原来的 foo() 将不允许自己被传递给 const 对象。该提议将允许它们,因此您失去了最初提供的一些安全性。您可以通过将 foo 的 const 类型版本重命名为类似于 foo_for_temp 来弥补这一点。然后,调用者就会知道函数的意图。

【讨论】:

  • 如果 non-temporary 是 const-qualified 类型怎么办?
  • @AndyProwl:上面的代码无法区分 const 对象和临时对象。但是 Irfy 的函数原型无论如何都不适用于 const 限定类型。
  • 确实,这意味着它会编译,而原始函数在使用const-qualified 类型的参数调用时不会(并且不应该)编译。
  • @AndyProwl:我不知道这项技术。问题基本上是:临时变量可以按值传递吗?我的回答是:是的,你自己复制它们。
  • 这是解决我的问题的有效方法,并且在实践中效果很好。事实上,我不需要传递 const 限定的对象。
【解决方案3】:

一个但危险的解决方案是将 const T & 作为函数参数,然后将 const_cast 传递给 T&。您必须小心传递给函数的内容,因为它很容易导致未定义的行为:

template <class T>
void foo(const T &ct)
{
    T &t = const_cast<T>( ct );
    // ...
}

【讨论】:

    猜你喜欢
    • 2019-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 2023-02-22
    • 2019-12-10
    • 1970-01-01
    相关资源
    最近更新 更多