昨天我遇到了一个 g++ (3.4.6) 编译器问题,我使用 Intel (9.0) 编译器编译的代码没有问题。这是显示所发生情况的代码片段:
template<typename A, typename B>
class Foo { };
struct Bar {
void method ( Foo<int,int> const& stuff = Foo<int,int>() );
};
g++ 编译器错误是:
foo.cpp:5: error: expected `,' or `...' before '>' token
foo.cpp:5: error: wrong number of template arguments (1, should be 2)
foo.cpp:2: error: provided for `template<class A, class B> struct Foo'
foo.cpp:5: error: default argument missing for parameter 2 of `void Bar::method(const Foo<int, int>&, int)'
显然,以这种方式编写时不接受默认参数,并且编译器假设指定了一个新的函数参数而不是第二个模板参数,然后它期望一个默认值,因为 stuff 参数有一个。我可以通过创建一个 typedef 来帮助编译器,然后一切都可以正常编译:
template<typename A, typename B>
class Foo { };
struct Bar {
typedef Foo<int,int> FooType;
void method ( FooType const& stuff = FooType() );
};
所以我可以解决我的问题,但我不明白发生了什么。我在这里错过了 C++(模板?)语言功能,我做错了什么,还是 g++ 编译器不接受第一段代码是错误的?
请注意顺便说一句,这也可以编译......
template<typename A, typename B>
class Foo { };
void method ( Foo<int,int> const& stuff = Foo<int,int>() );
最佳答案
我不太确定这是 g++(自版本 4.2.4 起)中的错误。该代码现在通过了 g++ 4.4(请参阅下面的更新)。为了让此代码为其他版本的编译器编译,您可以在默认参数周围添加一组括号:
template<typename A, typename B>
class Foo { };
struct Bar {
void method ( Foo<int,int> const& stuff = ( Foo<int,int>() ) );
};
IMO,这些括号是必要的,因为还有一个额外的要求,即默认参数可以引用类的成员,该成员可能稍后在类主体中声明:
struct Bar {
void method ( int i = j); // 'j' not declared yet
static const int j = 0;
};
上面的代码是合法的,在解析'method'的声明时还没有看到成员'j'。因此,编译器只能使用语法 检查(即匹配括号和逗号)来解析默认参数。当 g++ 解析您的原始声明时,它实际看到的是以下内容:
void method ( Foo<int,int> const& stuff = Foo<int // Arg 1 with dflt.
, int>() ); // Arg 2 - syntax error
添加额外的一组括号可确保正确处理默认参数。
以下情况显示了 g++ 成功但 Comeau 仍然生成语法错误的示例:
template<int J, int K>
class Foo { };
struct Bar {
void method ( Foo<0, 0> const & i = ( Foo<j, k> () ) );
static const int j = 0;
static const int k = 0;
};
编辑:
作为对评论的回应:“你也可以在那里进行带有多个参数的函数调用”,这不会导致问题的原因是函数调用中的逗号被括在括号中:
int foo (int, int, int);
struct Bar {
void method ( int j =
foo (0, 0, 0) ); // Comma's here are inside ( )
};
因此,可以仅使用表达式的语法 来解析它。在 C++ 中,所有的 '(' 必须与 ')' 匹配,所以这很容易解析。这里出现问题的原因是“<”不需要匹配,因为它在 c++="">”不需要匹配,因为它在><>
template<int I, int J>
class Foo { };
struct Bar {
template <typename T> struct Y { };
void method ( ::Foo<0,0> const& stuff = Foo<10 , Y < int > = Y<int>() );
struct X {
::Foo<0, 0> operator< (int);
};
static X Foo;
};
上面的 "Foo<10"是对 'x'="" 中定义的="">10"是对><"的调用,而不是模板参数列表的开头。同样,comeau 在上述代码上生成了语法错误,而="" g++(包括="">"的调用,而不是模板参数列表的开头。同样,comeau>
仅供引用,适当的引用是 8.3.6/5 中的注释:
[Note: in member function declarations, names in default argument expressions are looked up as described in 3.4.1...
然后在 3.4.1/8
A name used in the definition of a member function (9.3) of class X following the function’s declaratorid29) shall be declared in one of the following ways:
...
— shall be a member of class X or be a member of a base class of X (10.2), or
此处的项目符号是强制编译器“延迟”查找默认参数含义的部分,直到声明所有类成员为止。
<更新>更新>
正如“Employed Russian”所指出的,g++ 4.4 现在能够解析所有这些示例。然而,直到 DR已由 C++ 标准委员会解决,我还没有准备好将其称为“错误”。我相信需要长期的额外括号以确保对其他编译器/工具(甚至可能是 g++ 的 future 版本)的可移植性。
根据我的经验,C++ 标准并未规定编译器供应商都应使用相同的解析器技术,而且他们也不能期望所有技术都同样强大。因此,解析需求通常不需要供应商执行超人的壮举。为了说明这一点,请考虑以下两个示例:
typedef T::TYPE TYPE;
T::TYPE t;
如果“T”是相关的,则给定每个上下文“TYPE”必须是一个类型名称,但是标准仍然需要类型名称 关键字。这些示例是明确的,只能表示一件事,但是标准(为了允许所有解析器技术)仍然需要 typename 关键字。
只要额外的括号允许代码解析,未能解析这些示例的编译器仍然是“符合标准的”,DR 可能会以这样一种方式被解决。
关于c++ - 默认模板类参数混淆了 g++?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23061912/
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我的瘦服务器配置了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_”……这
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
我有一些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
我正在为一个项目制作一个简单的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"
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)
我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问
两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option
我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano