我一直在努力解决 this question 中描述的问题(将模板函数声明为模板类的 friend ),我相信第二个答案是我想要做的(转发声明模板函数,然后将特化命名为 friend )。我有一个问题,即稍微不同的解决方案实际上是正确的还是恰好适用于 Visual C++ 2008。
测试代码为:
#include <iostream>
// forward declarations
template <typename T>
class test;
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t);
template <typename T>
class test {
friend std::ostream& operator<< <T>(std::ostream &out, const test<T> &t);
// alternative friend declaration
// template <typename U>
// friend std::ostream& operator<<(std::ostream &out, const test<T> &t);
// rest of class
};
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t) {
// output function defined here
}
首先,我发现一件奇怪的事情是,如果我更改 operator<< 的前向声明所以它不匹配(例如 std::ostream& operator<<(std::ostream &out, int fake); ,一切仍然编译并正常工作(要清楚,我不需要定义这样的函数,只需声明它)。但是,如链接到问题,删除前向声明会导致问题,因为编译器似乎认为我正在声明数据成员而不是友元函数。我很确定此行为是 Visual C++ 2008 错误。
有趣的是,当我删除前向声明并在上面的代码中使用替代的友元声明时。注意模板参数 U没有出现在以下签名中。此方法也可以正确编译和工作(无需更改任何其他内容)。我的问题是这是否符合标准或 Visual C++ 2008 的特性(我在我的引用书中找不到好的答案)。
注意当 friend 声明template <typename U> friend ... const test<U> &t);也有效,这实际上给出了运算符的每个实例 friend访问 test 的任何实例,而我想要的是 test<T> 的私有(private)成员应该只能从 operator<< <T> 访问.我通过实例化 test<int> 来测试它在operator<<里面并访问私有(private)成员;当我尝试输出 test<double> 时,这应该会导致编译错误.
概要:在上面的代码中删除前向声明并切换到替代友元声明似乎产生相同的结果(在 Visual C++ 2008 中)——这段代码真的正确吗?
更新:上述任何对代码的修改在 gcc 下都不起作用,所以我猜测这些是 Visual C++ 编译器中的错误或“功能”。不过,我还是很感谢熟悉该标准的人提供的见解。
最佳答案
...如果我更改 operator<>
友元函数应该被看作是一种非常特殊的声明类型。本质上,编译器会做足够的工作来解析声明,但是除非您真正特化该类,否则不会进行语义检查。
进行建议的修改后,如果您随后实例化 test您将收到有关声明不匹配的错误消息:
template class test<int>;
...但是...删除前向声明会导致问题
编译器会尝试解析声明并存储它,直到类模板被特化为止。在解析期间,编译器到达 <在声明中:
friend std::ostream& operator<< <
operator<< 的唯一途径后面可以跟< is 如果它是一个模板,那么会进行查找以检查它是否是一个模板。如果找到函数模板,则 <被认为是模板参数的开始。
当您删除前向声明时,找不到模板并且 operator<<被认为是一个对象。 (这也是为什么当您添加 using namespace std 时代码会继续编译,因为必须有 operator<< 的模板声明)。
...当我删除前向声明并在上面的代码中使用替代的友元声明时。请注意,模板参数 U 未出现在以下签名中...
不要求所有模板参数都用于函数模板的参数中。替代声明用于新函数模板,只有在命名空间中声明并指定显式模板参数时才可调用。
一个简单的例子是:
class A {};
template <typename T> A & operator<<(A &, int);
void foo () {
A a;
operator<< <int> (a, 10);
}
...这段代码真的正确吗?..
好吧,这有两个部分。首先是备选友元函数不引用作用域后面的声明:
template <typename T>
class test {
template <typename U>
friend std::ostream& operator<<(std::ostream &out, const test<T> &t);
};
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t); // NOT FRIEND!
friend 函数实际上会在每个特化的命名空间中声明:
template <typename U>
std::ostream& operator<<(std::ostream &out, const test<int> &t);
template <typename U>
std::ostream& operator<<(std::ostream &out, const test<char> &t);
template <typename U>
std::ostream& operator<<(std::ostream &out, const test<float> &t);
operator<< <U>的每个特化将根据其参数的类型访问特定的特化 test<T> .所以本质上,访问是根据您的需要受到限制的。然而,正如我之前提到的,这些函数基本上不能用作运算符,因为您必须使用函数调用语法:
int main ()
{
test<int> t;
operator<< <int> (std << cout, t);
operator<< <float> (std << cout, t);
operator<< <char> (std << cout, t);
}
根据上一个问题的答案,您可以使用 litb 建议的前向声明, 或者你按照 Dr_Asik's 定义 friend 函数内联回答(这可能是我会做的)。
更新:第二条评论
...改变课前的前置声明;类的还是符合我后面实现的功能...
正如我上面所指出的,编译器检查是否 operator<<当它看到 < 时是一个模板在声明中:
friend std::ostream& operator<< <
它通过查找名称并检查它是否是模板来完成此操作。只要你有一个虚拟的前向声明,那么这就会“欺骗”编译器将你的 friend 视为模板名称,因此 <被认为是模板参数列表的开始。
稍后,当您实例化该类时,您确实有一个有效的模板可以匹配。本质上,您只是在欺骗编译器将友元视为模板特化。
您可以在此处执行此操作,因为(正如我之前所说)此时没有进行语义检查。
关于c++ - 模板类的模板友元函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1787143/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
大家好!我想知道Ruby中未使用语法ClassName.method_name调用的方法是如何工作的。我头脑中的一些是puts、print、gets、chomp。可以在不使用点运算符的情况下调用这些方法。为什么是这样?他们来自哪里?我怎样才能看到这些方法的完整列表? 最佳答案 Kernel中的所有方法都可用于Object类的所有对象或从Object派生的任何类。您可以使用Kernel.instance_methods列出它们。 关于没有类的Ruby方法?,我们在StackOverflow
我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下
如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只