【发布时间】:2012-10-22 16:04:21
【问题描述】:
考虑以下简单的make_pair 类:
template <class X, class Y>
struct Pair
{
X x;
Y y;
};
此外,我们将创建一个简单的类来显示任何移动/复制:
struct C
{
C(int n_) : n(n_) {};
C(const C& x) { n = x.n; std::cout << "Copy: " << n << std::endl; }
C(C&& x) { n = x.n; std::cout << "Move: " << n << std::endl; }
int n;
};
然后我们可以运行:
auto z1 = Pair<C, C>{C(1),C(2)};
并且没有输出,C 没有被移动或复制。
但是,我们必须在构造函数Pair 中指定类型。假设我们想推断这些。我们可以这样做:
template <class X, class Y>
Pair<X, Y> make_pair(X&& x, Y&& y)
{
return Pair<X, Y>{std::forward<X>(x), std::forward<Y>(y)};
}
然后我们可以这样做:
auto z2 = make_pair(C(3),C(4));
但这会打印出来:
Move: 3
Move: 4
如果C 是堆分配类型,则没有问题,但如果是堆栈分配类型,则移动基本上是复制。
然后让我们定义这个宏:
#define MAKE_PAIR(x,y) decltype(make_pair(x,y)){x,y}
那么我们可以这样做:
auto z3 = MAKE_PAIR(C(5),C(6));
这确实是类型推断并且不需要移动。但是我们需要做一个宏,我觉得有点乱,也阻止了我们使用操作符来做这种事情。
是否有执行以下操作的解决方案:
(1) 推导类型(如 2 和 3)
(2) 不需要复制或移动(如 1 和 3)
(3) 不需要宏(如 1 和 2)
我能得到的最好结果是三分之二,但三分之三肯定是可能的吗?我无法想象 C++ 会强迫人们使用宏来获得我所追求的行为,因为显然 C++ 正在远离宏。
代码是here。
【问题讨论】:
-
I can make it happen for copies,不确定动作。 (注意:如果您传递左值,您的
make_pair将创建一个Pair<T&, U&>。;)因此,没有副本。) -
如果您的基于堆栈的类太大而成为问题,那您就错了。
-
@Xeo:呵呵,我想知道这是故意的还是我应该说什么。一点点
remove_reference或decay很可能在那个 maker 函数中是有序的。 -
@KerrekSB,Xeo:这不是特别设计的,但这不是主要问题。我遇到的主要问题是临时工应该就地建造。它们在示例 (1) 和 (3) 中,但不在 (2) 中。
-
当要求我的编译器进行优化时,虽然特殊成员的输出仍在执行,但对
C、Pair和make_pair的所有引用都将被删除。可以肯定的是,从保留其副作用的意义上说,副本并没有被忽略。但无论如何,这些对象都不在这里。考虑到副作用可能是为了仪表而放在这里的,所以我真的不知道问题是什么。
标签: c++ templates constructor c++11