【发布时间】:2014-08-28 14:32:53
【问题描述】:
我正在使用以下代码测试通用参考,
template <typename T>
vector<T> attach_(vector<T> xs, T&& x) {
xs.push_back(std::forward<T>(x));
return xs;
}
int main() {
int k = 2;
attach_(std::move(vector<int>{1,2,3}),k); //not OK
attach_(std::move(vector<int>{1,2,3}),(int&)k); //not OK
attach_(std::move(vector<int>{1,2,3}),(int)k); //OK
attach_(std::move(vector<int>{1,2,3}),2); //OK
}
得到一个错误:
no matching function for call to 'attach_(std::remove_reference<std::vector<int> >::type, int&)'
attach_(std::move(vector<int>{1,2,3}),k);
note: template argument deduction/substitution failed:
note: deduced conflicting types for parameter 'T' ('int' and 'int&')
attach_(std::move(vector<int>{1,2,3}),k);
SO 有一个关于 const 引用的类似错误Error message "deduced conflicting types for parameter 'const T'" 的问题。
我还测试了其他一些情况,其中一些使用了类型转换。有些工作,有些则没有。
我听说像T&& 这样的通用引用可以匹配所有内容。为什么这里会失败?
第二个问题是,如何键入 attach_ 以确保移动语义适用于 xs 和 x 以获取适当的输入?最终,我想要以下变体:
for(int i = 0; i < 100; i++)
xs = attach_(xs,values[i])
工作时不要制作不必要的副本。
(这是用gcc4.8.1测试的,使用g++ -std=c++11 test.cpp)
谢谢
-- 编辑 ---
感谢大家的精彩回答。
所以我现在明白,对于这种情况,仅使用按值传递并移动 T 是有效的。如果在循环中使用,向量 xs 在参数传递和返回中不会被不必要地复制,对吧?
我问了一个相关问题When is a const reference better than pass-by-value in C++11?。在那里,我有一个例子,每个人都说 pass-by-vale 是个坏主意:
int hd(vector<int> a) {
return a[0];
}
是否有可能使用通用引用来处理本文中的hd 情况和attach_ 情况以避免不必要的复制?
再次感谢。
--- EDIT2 ---
所以,我测试了答案中的版本以及下面的const 参考版本。优化不用于暴露任何潜在问题。 const ref 版本是最糟糕的,因为它强制复制。如果 std::move(a) 用于向量,则其他所有内容都具有相同的速度,但原始的 push_call 调用更快。我想优化可以消除这种差异。我猜这个测试(或者可能是 int 类型)不够大,无法显示push_back(x) 和push_back(std::move(x)) 之间的区别
#include <vector>
#include <iostream>
#include <chrono>
using namespace std;
template <class T>
vector<T> attach(vector<T> v, T x) {
v.push_back(x);
return v;
}
template <typename T>
vector<T> attach1(vector<T> xs, T x) {
xs.push_back(std::move(x));
return xs;
}
template <typename T, typename E = typename std::remove_reference<T>::type>
std::vector<E> attach2(std::vector<E> xs, T&& x) {
xs.push_back(std::forward<T>(x));
return xs;
}
template <typename C, typename T> C attach3(C&& xs, T&& x) {
xs.push_back(std::move<T>(x));
return std::forward<C>(xs);
}
template <class T>
vector<T> attach4(const vector<T>& v, T x) {
vector<T> ret = v;
ret.push_back(x);
return std::move(ret);
}
using namespace std::chrono;
int main() {
int N = 100000;
vector<int> a;
auto time = high_resolution_clock::now();
for (int i = 0; i < N; i++) {
//a.push_back(i); //0s
//a = attach(a,i); //15s
//a = attach(std::move(a),i); //0.03s
//a = attach2(std::move(a),i); //0.03s
a = attach3(std::move(a),i); //0.03s
//a = attach4(std::move(a),i); //14.9s
}
cout << duration_cast<duration<double>>(high_resolution_clock::now() - time).count() << endl;
}
【问题讨论】:
-
那里没有通用参考。 UR 必须只有一个函数参数。
-
哦,我明白了。所以不仅我们不能在 T&& 中添加 const 等,而且我们不能有任何其他类型涉及 T?
-
那会彻底失败,不是吗...
-
我还在学习这个。观看了 Scott 的一段视频,大约有两个 & 符号。为什么人们不使用 ` 或其他东西作为正确的引用,而是想出所有这些规则和特殊情况?
标签: c++ c++11 type-deduction