我正在尝试找到一个工作类型特征来检测给定类型是否具有 std::ostream 的左移运算符重载(例如,可与 std::cout 或 boost::lexical_cast 互操作)。我在 boost::has_left_shift 上取得了成功除了类型是 POD 或 std::string 的 STL 容器的情况类型。我怀疑这与 STL 类型或 operator< 函数的特化有关。使用="">std::ostream 的有效左移运算符一般识别类型的正确方法是什么? ?如果那不可行,是否有单独的方法来检测 POD 或 std::string 类型的 STL 容器上左移运算符的过载?
下面的代码显示了我目前正在使用的内容,并演示了如何 boost::has_left_shift未能检测到过载 operator<<函数,即使它在下一行被调用。该程序在 GCC 4.5.1 或更高版本和 clang 3.1 中编译和运行。
为了避免明显的 react ,我尝试替换模板化的 operator<<各种类型的特定版本的功能用于无济于事。我还为这两种类型尝试了 const-ness 和 l-value/r-value 说明符的各种组合(各种调整使我看到一条编译器消息,指向带有 r-value ostream 的 operator<< 重载)。我也尝试过实现我自己的特征,它最多给我与 boost::has_left_shift 相同的结果。 .
在此先感谢您提供的任何帮助。如果可以包含对为什么会发生这种行为以及解决方案如何工作的详尽解释,我也将不胜感激。我正在扩展我的模板知识的极限,很想知道为什么这不像我想象的那样有效。
#include <string>
#include <vector>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/type_traits/has_left_shift.hpp>
using namespace std;
struct Point {
int x;
int y;
Point(int x, int y) : x(x), y(y) {}
string getStr() const { return "("+boost::lexical_cast<string>(x)+","+boost::lexical_cast<string>(y)+")"; }
};
ostream& operator<<(ostream& stream, const Point& p)
{
stream << p.getStr();
return stream;
}
template <typename T>
ostream& operator<<(ostream& stream, const std::vector<T>& v)
{
stream << "[";
for(auto it = v.begin(); it != v.end(); ++it)
{
if(it != v.begin())
stream << ", ";
stream << *it;
}
stream << "]";
return stream;
}
template <typename T>
void print(const string& name, T& t)
{
cout << name << " has left shift = " << boost::has_left_shift<ostream , T>::value << endl;
cout << "t = " << t << endl << endl;
}
int main()
{
cout << boolalpha;
int i = 1;
print("int", i);
string s = "asdf";
print("std::string", s);
Point p(2,3);
print("Point", p);
vector<int> vi({1, 2, 3});
print("std::vector<int>", vi);
vector<string> vs({"x", "y", "z"});
print("std::vector<std::string>", vs);
vector<Point> vp({Point(1,2), Point(3,4), Point(5,6)});
print("std::vector<Point>", vp);
}
最佳答案
它不起作用的原因是 C++ 有时有令人惊讶的(但动机良好的)解析函数调用的规则。特别是,名称查找首先在调用发生的命名空间和参数的命名空间(对于 UDT)中执行:如果找到具有匹配名称(或匹配的内置运算符)的函数,则选择它(或者如果找到多个,则执行重载决议)。
仅当在参数的命名空间中找不到具有匹配名称的函数时,才会检查父命名空间。如果找到具有匹配名称的函数但无法解析调用,或者调用不明确,编译器将不会继续在父命名空间中查找以期找到更好或明确的匹配:相反,它会结论是没有办法解决调用。
很好地解释了这种机制in this presentation by Stephan T. Lavavej在this old article by Herb Sutter .
在您的例子中,检查此运算符是否存在的函数在 boost 中命名空间。您的论点来自 std命名空间 ( ostream , string , vector ) 或 POD ( int )。在std命名空间,operator << 的不可行 重载存在,因此编译器不会费心在定义重载的父(全局)命名空间中查找。它会简单地得出结论,在 boost 中完成的(模拟)调用命名空间检查是否operator <<已定义无法解析。
现在boost::has_left_shift很可能有一些 SFINAE 机制将编译错误转化为失败的替换,并将分配 false到 value静态变量。
更新:
答案的原始部分解释了为什么这不起作用。现在让我们看看是否有办法解决它。由于使用了 ADL,并且 std命名空间包含不可行的重载 operator << , 事实上 阻止了解决调用的尝试,人们可能会想移动 operator << 的可行 重载。从全局命名空间到 std命名空间。
唉,扩展std命名空间(如果我们要添加 operator << 的新重载,我们就会这样做)被 C++ 标准禁止。允许的是专门化 std 中定义的模板函数。命名空间(除非另有说明);然而,这对我们没有帮助,因为没有模板的参数可以被 vector<int> 专门化。 .此外,函数模板不能部分特化,这会使事情变得更加笨拙。
不过还有最后一种可能性:将重载添加到调用解析发生的命名空间。这是 Boost.TypeTraits 机制内部的某个地方。特别是,我们感兴趣的是进行调用的命名空间的名称。
在当前版本的库中,它恰好是 boost::detail::has_left_shift_impl ,但我不确定这在不同的 Boost 版本中的可移植性如何。
但是,如果您真的需要解决方法,您可以在该命名空间中声明您的运算符:
namespace boost
{
namespace detail
{
namespace has_left_shift_impl
{
ostream& operator<<(ostream& stream, const Point& p)
{
stream << p.getStr();
return stream;
}
template <typename T>
std::ostream& operator<<(std::ostream& stream, const std::vector<T>& v)
{
stream << "[";
for(auto it = v.begin(); it != v.end(); ++it)
{
if(it != v.begin())
stream << ", ";
stream << *it;
}
stream << "]";
return stream;
}
}
}
}
一切都会开始运作。
不过有一个警告:虽然它可以在 GCC 4.7.2 上正常编译和运行,并具有预期的输出。但是,Clang 3.2 似乎要求在 boost::details::has_left_shift_impl 中定义重载。 之前 has_left_shift.hpp包含 header 。我认为这是一个错误。
关于c++ - 测试是否存在左移运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14569768/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我有一些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
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test