在回答关于 SO 的另一个问题时,我遇到了一个有点可疑的 gcc 编译器错误。有问题的片段是
template <class T> class A;
template <class T, class U>
void operator*(A<T>, A<U>);
template <class T>
class A {
friend void ::operator*(A<T>, A<T>);
...
最后一行给出了著名的警告
friend declaration '
void operator*(A<T>, A<T>)' declares a non-template function
稍后会导致硬错误。完整代码可见here .
现在,问题是我认为这种行为不合适。 [temp.friend]/1 中的标准说:
For a friend function declaration that is not a template declaration:
— if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function template, otherwise
— if the name of the friend is a qualified-id and a matching nontemplate function is found in the specified class or namespace, the friend declaration refers to that function, otherwise,
— if the name of the friend is a qualified-id and a matching specialization of a template function is found in the specified class or namespace, the friend declaration refers to that function specialization, otherwise,
这是 C++03; C++11 包含类似的子句
模板的特化由 [temp.spec]/4 定义:
... A specialization is a class, function, or class member that is either instantiated or explicitly specialized (14.7.3).
和 [temp.fct.spec]/1:
A function instantiated from a function template is called a function template specialization; so is an explicit specialization of a function template. Template arguments can either be explicitly specified ...
[temp.arg.explicit]/2 说的是关于为函数规范指定模板参数列表:
A template argument list may be specified when referring to a specialization of a function template
...
— in a friend declaration.
Trailing template arguments that can be deduced (14.8.2) may be omitted from the list of explicit template-arguments. If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted.
因此,通过 [temp.fct.spec]/1,::operator*<T,T>(A<T>, A<T>)是函数模板特化;由于可以推导出模板参数,因此可以称为::operator*(A<T>, A<T>) .所以我得出结论,友元声明中的 qualified-id 表示函数模板特化。
我认为满足了强调的条件;因此,友元声明应该与具有运算符模板(隐式)特化的类成为友元。然而,gcc 不这么认为,并继续讨论第四个项目符号,它只涉及由非限定 id 指定的 friend ,即使该 friend 实际上是由限定 id 命名的。
在这种情况下我的解释正确还是 gcc 正确?
最佳答案
我相信 gcc 是正确的。
首先是当前的措辞:
if the name of the friend is a qualified-id and a matching function template is found in the specified class or namespace, the friend declaration refers to the deduced specialization of that function template (14.8.2.6), otherwise
来自[14.8.2.6 从函数声明中推导模板参数]:
1 In a declaration whose declarator-id refers to a specialization of a function template, template argument deduction is performed to identify the specialization to which the declaration refers. Specifically, this is done for explicit instantiations (14.7.2), explicit specializations (14.7.3), and certain friend declarations (14.5.4). This is also done to determine whether a deallocation function template specialization matches a placement operator new (3.7.4.2, 5.3.4). In all these cases, P is the type of the function template being considered as a potential match and A is either the function type from the declaration or the type of the deallocation function that would match the placement operator new as described in 5.3.4. The deduction is done as described in 14.8.2.5.
2 If, for the set of function templates so considered, there is either no match or more than one match after partial ordering has been considered (14.5.6.2), deduction fails and, in the declaration cases, the program is ill-formed.
在您的情况下,未执行模板参数推导,因为 declarator-id 未引用特化。我认为重要的部分是 whose declarator-id refers to a specialization作为这一切发生的条件。简而言之,您需要 <> 14.8.2.6p1 中的第一句话发生(如果我没看错的话)。
更新 让我们分解一下这种情况下的 declarator-id 是什么:
qualified-id:
nested-name-specifier templateopt unqualified-id
:: identifier
:: operator-function-id
:: literal-operator-id
:: template-id
从上面的语法可以看出,void ::operator*(A<T>, A<T>)是 :: operator-function-id并且不是 :: template-id .这意味着语法永远不能声明模板函数(如错误消息中所述)。要使其成为模板 ID,您必须使用 operator-function-id < template-argument-listopt>语法。
关于c++ - 与模板特化成为 friend 时可能出现 gcc 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13521546/
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
我的瘦服务器配置了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_”……这
我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e
我遵循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
我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee