- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
昨天我遇到了一个 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' 中定义的 "operator<"的调用,而不是模板参数列表的开头。同样,Comeau 在上述代码上生成了语法错误,而 g++(包括 3.2.3)正确地解析了它。
仅供引用,适当的引用是 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/851584/
我目前正在尝试让 g++ 工作,并查看 http://gcc.gnu.org/install/build.html ,我似乎找不到它在哪里说如何“执行编译器的 3 阶段 bootstrap ”。我在哪
James Powell 在他对即将举行的演示文稿的简短描述中说,他自豪地发明了最粗糙的 Python 单行代码之一: (None for g in g if (yield from g) and F
请告诉我我的证明是否正确 We have a connected graph, and specific vertex u in V(G). Suppose we compute the dfs tr
下面的test2和test3结果是不同的。 我对此感到困惑,因为它看起来像相同的逻辑,并且与linux bash ||逻辑不同。 $data = @( [PSCustomObject]@{St
我试图找到一个明确的 G 代码语法规范,而不是单个 G 代码的含义,我无处不在的规范,我的意思是详细的语法规范,目的是编写解析器。 我编写解析器没有问题,我只是在寻找语法规范,例如。我知道您不必总是为
我写了这个 mixin,但它循环了很多时间。你能帮我优化我的代码吗?或者你能建议一些其他的东西来获得想要的结果吗? dfgdfgsdfgsdf 最佳答案 希望这就是您要找的。 $spaces: (4,
默认情况下,g++ 似乎会省略未使用的类内定义方法的代码。示例 from my previous question : struct Foo { void bar() {} void baz(
是否可以将文件内容通过管道传送到 g++编译程序? 我想这样做是因为我想使用数据库中的文件而不是磁盘上的物理文件。可以通过我制作的 API 轻松检索文件内容。 例如,我想做这样的事情: g++ con
如何profile c++代码获取每行代码的调用次数和消耗时间,就像profile工具一样在 Matlab 中呢? 我尝试使用-fprofile-arcs之类的东西,但它只生成代码覆盖率报告,其中可以
如何在几行代码上禁用所有警告。可以使用 GCC 诊断功能禁用特定警告,但是否有针对所有警告的标志。我尝试了这个方法,但不起作用 #pragma GCC diagnostic push #pragma
我有一个链接到 opencv 2.2 的可执行文件。但是,我删除了 opencv 2.2 并安装了 opencv 2.3。 问题是,有没有办法在不重新编译整个源代码的情况下将这个可执行文件链接到新的共
在编译带有一些标志的以下文件时,是否可以让 g++ 显示错误? #include using namespace std; int main() { int arr[ 2 ]; cout
在学习 Haskell 时,我遇到了一个挑战,要找到两个函数 f 和 g,例如 f g 和 f 。 g 是等价的(并且是总计,因此像 f = undefined 或 f = (.) f 这样的东西不算
根据我的理解,Theta 位于 Big O 和 Omega 之间,但我看到了这个声明,但我无法理解为什么交集会出现在这里。我能否对 Θ(g(n)) = O(g(n)) ∩ Ω(g(n)) 获得数学和分
我需要为这个递归函数编写一个迭代函数。 int funcRec(int n){ if(n>1) { return 2*funcRec(n - 1) + 3*funcRec(n
我在 github repository 上有代码示例并在 travis-ci 上创建了一个构建便于复制。 最小的、完整的和可验证的例子 可能不是最小的,但我相信它足够小 它使用 boost.inte
编辑:我们将调用箭头 p纯如果存在这样的函数f即:p = arr f . 我试图更好地掌握 Haskell 中的 Arrows,我想弄清楚什么时候 f >>> (g &&& h) = (f >>> g
我有两个(或更多)函数定义为: val functionM: String => Option[Int] = s => Some(s.length) val functionM2: Int => Op
好像是的。任何直观或严肃的证据都值得赞赏。 最佳答案 没有。 我认为您的问题等同于:给定函数 f 和 g,f 是 O(g) 或 g 是 O(f) 是否总是正确的?这在 SE Computer Scie
如果我设法证明 f(n) = o(g(n))(小 o),那么这两个函数的总和 f( n) + g(n) 应该被“更大”的函数 g(n) 紧紧束缚。 然而,我在证明这一点时遇到了一些麻烦。 最佳答案 以
我是一名优秀的程序员,十分优秀!