草庐IT

c++ - 推断出参数 'T' 的冲突类型以供通用引用

coder 2024-01-31 原文

我正在使用以下代码测试通用引用,

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 有一个类似错误的问题 Error message "deduced conflicting types for parameter 'const T'"关于 const 引用。

我还测试了其他一些案例,其中一些案例进行了类型转换。有些有效,有些则无效。

我听说像 T&& 这样的通用引用可以匹配所有内容。为什么这里失败了?

第二个问题是,如何键入 attach_ 以确保移动语义对 xsx 都有效以进行适当的输入?最后,我想要以下变体:

for(int i = 0; i < 100; i++)
   xs = attach_(xs,values[i])

工作时不要制作不必要的拷贝。

(这是用gcc4.8.1测试的,使用g++ -std=c++11 test.cpp)

谢谢

-- 编辑 ---

感谢大家的精彩回答。

所以我现在明白了,对于这种情况,使用按值传递并移动 T 是很有效的。如果在循环中使用, vector 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_ 情况以避免不必要的复制?

再次感谢。

--- 编辑2 ---

因此,我测试了答案中的版本以及下面的 const 引用版本。优化不用于暴露任何潜在问题。 const ref 版本是最差的,因为它强制复制。如果将 std::move(a) 用于 vector ,则其他一切都具有相同的速度,除了原始 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;

}

最佳答案

通用引用的工作方式是这样的:如果你传入一个右值,那么 T将被推断为 int (或其他一些非引用类型),因为那时 T&&是右值引用类型。但是如果你传入一个左值,那么T将被推断为 int& (或其他一些左值引用类型),因为那时 T&&将是左值引用类型(因为左值引用和右值引用“折叠”在一起成为左值引用)。

所以在你传递一个左值的情况下,你有一个问题,因为你不能有 vector<T>什么时候T是引用类型。

你应该只按值传递,

template <typename T>
std::vector<T> attach_(std::vector<T> xs, T x) {
  xs.push_back(std::move(x));
  return xs;
}

这可能看起来效率较低,但事实并非如此。如果你传入一个右值,它将被移动一次到 x 中, 并再次移动到 vector 中。如果你传入一个左值,它将被复制一次到 x 中, 他们移动到 vector 中。这与通过引用传递相同:左值一个拷贝,右值零个拷贝。

出于教育目的,您可以使用通用引用来做到这一点:

template <typename T, typename E = typename std::remove_reference<T>::type>
std::vector<E> attach_(std::vector<E> xs, T&& x) {
  xs.push_back(std::forward<T>(x));
  return xs;
}

这确保当您传递一个左值时, vector 元素类型是非引用类型。但按值传递确实更好。

关于c++ - 推断出参数 'T' 的冲突类型以供通用引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24621954/

有关c++ - 推断出参数 'T' 的冲突类型以供通用引用的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  3. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  4. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  7. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  8. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  9. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  10. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

随机推荐