草庐IT

成员模板的 C++ 混淆属性名称

coder 2023-06-01 原文

我发现,当从模板类型 (v.foo) 的变量访问非模板属性 (T& v) 时,如果有模板,C++ 可能会误以为它是成员模板同名函数 ( template class <T> void foo() )。如何从 C++ 规范中解释这一点?考虑这个简单的程序:

#include <cassert>

/** Determine whether the 'foo' attribute of an object is negative. */
template <class T>
bool foo_negative(T& v)
{
    return v.foo < 0;
}

struct X
{
    int foo;
};

int main()
{
    X x;
    x.foo = 5;
    assert(!foo_negative(x));
    return 0;
}

我们有一个模板函数foo_negative它接受任何类型的对象并确定其 foo 属性是否为负。 main函数实例化 foo_negative与 [T = X]。该程序编译运行,没有任何输出。

现在,将此函数添加到程序顶部:

template <class T>
void foo()
{
}

用 G++ 4.6.3 编译会导致这个编译器错误:

funcs.cpp: In function ‘bool foo_negative(T&)’:
funcs.cpp:13:14: error: parse error in template argument list
funcs.cpp: In function ‘bool foo_negative(T&) [with T = X]’:
funcs.cpp:25:5:   instantiated from here
funcs.cpp:13:14: error: ‘foo’ is not a member template function

(其中第 13 行是 return v.foo < 0,第 25 行是 assert(!foo_negative(x))。)

Clang 会产生类似的错误。

什么?添加一个从未调用过的不相关函数如何将语法错误引入有效程序?解析时foo_negative ,编译器不知道 v 的类型,而且至关重要的是,它不知道 v.foo是成员(member)模板还是普通成员(member)。显然,它必须在解析时(在模板实例化之前)决定是将其视为成员模板还是普通成员。

如果它认为 v.foo是成员(member)模板,则< 0被视为通过0作为模板参数,并且缺少 > ,因此语法错误。那么,当foo_negative用 [T = X] 实例化,还有另一个错误,因为 X::foo不是成员模板。

但它为什么会认为 v.foo是成员(member)模板吗?这种模糊性正是 template关键字是:如果我写了v.template foo ,然后我会明确告诉 C++ 期待一个成员模板,但我没有使用 template关键词!我没有提到成员模板,所以它应该假设它是一个普通成员。有一个与成员同名的 function 的事实不应该有任何影响。为什么会这样?不可能是编译器的bug,因为GCC和clang是一致的。

最佳答案

它看起来确实像一个编译器错误。

标准说:

After name lookup (3.4) finds that a name is a template-name or that an operator-function-id or a literal-operator-id refers to a set of overloaded functions any member of which is a function template if this is followed by a <, the < is always taken as the delimiter of a template-argument-list and never as the less-than operator.

在 3.4.5/1 中

In a class member access expression (5.2.5), if the . or -> token is immediately followed by an identifier followed by a <, the identifier must be looked up to determine whether the < is the beginning of a template argument list (14.2) or a less-than operator. The identifier is first looked up in the class of the object expression. If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template.

标准似乎没有表明名称查找可以在这里找到非成员函数模板。无论如何,< 的含义应该在模板定义时确定,而不是在实例化时确定(那时为时已晚)。

关于成员模板的 C++ 混淆属性名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10671406/

有关成员模板的 C++ 混淆属性名称的更多相关文章

  1. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

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

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

  4. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  5. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  6. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  7. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  8. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在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中能不能做到类似的简洁?我可以只

  9. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  10. ruby-on-rails - Mandrill API 模板 - 2

    我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h

随机推荐