这是从观察开始的。我改变了一些看起来有点像这样的代码(编辑:我在这里取出了指定的初始值设定项,原始代码中也没有):
struct S {
enum E { E1, E2 } member;
}
// file1.cc
S v1 = { S::E1 };
// file2.cc
S v2 = { S::S::E2 };
请注意,file2.cc
过分限定E2
。然而,这适用于g ++和clang ++。 (编辑2:这个特定虚拟机上的g ++是g ++ - 5.4.1,但是原始代码已经过了早期版本和后来的g ++版本,加上多个clang版本。)实际上,我们可以写一下:
S v3 = { S::S::S::S::S::S::S::E1 };
(无论我们喜欢多少S::
),无论我们喜欢什么。我改变了一些事情,以便S
不再是普通的struct
,而是一个模板化的,之后就停止了工作。没什么大不了的,但它让我感到好奇,所以我进行了实验。
如果我们将其更改为非POD类型:
struct S {
S() { std::cout << "made an S" << std::endl; }
enum E { E1, E2 } member;
}
(适当的#include
)不再允许。 Clang和g ++产生不同的诊断。以下是clang的抱怨:
namespace.cc:8:3: error: no matching constructor for initialization of 'S'
S x = { .member = S::S::E1 };
namespace.cc:3:8: note: candidate constructor (the implicit copy constructor)
not viable: cannot convert argument of incomplete type 'void' to
'const S &' for 1st argument
struct S {
^
namespace.cc:3:8: note: candidate constructor (the implicit move constructor)
not viable: cannot convert argument of incomplete type 'void' to 'S &&'
for 1st argument
struct S {
^
namespace.cc:4:3: note: candidate constructor not viable: requires 0 arguments,
but 1 was provided
S() { std::cout << "made an S\n"; }
^
1 error generated.
和g ++&#39; s:
namespace.cc:8:28: error: could not convert ‘{E1}’ from ‘<brace-enclosed initializer list>’ to ‘S’
S x = { .member = S::S::E1 };
这些似乎遵循不同的规则。这里发生了什么?
接下来,让我们尝试另一种滥用行为。这是整个计划:
#include <iostream>
struct S {
S() { std::cout << "made an S\n"; }
enum E { E1, E2 } member;
};
int main() {
std::cout << S::S::S::S::S::E1 << std::endl;
#ifdef DECL
S::S::S var;
#endif
return 0;
}
此代码在两个编译器中编译(不含-DDECL
):
$ clang++-3.9 -std=c++11 -Wall -O namespace.cc
$ ./a.out
0
$ g++ -Wall -std=c++11 -O namespace.cc
$ ./a.out
0
(尽管在早期代码中为变量S
初始化程序发出了投诉clang,但此处构建了{member
。但是,在main
中启用变量会导致失败g ++,但没有clang:
$ clang++-3.9 -std=c++11 -DDECL -Wall -O namespace.cc
$ ./a.out
0
made an S
$ g++ -std=c++11 -DDECL -Wall -O namespace.cc
namespace.cc: In function ‘int main()’:
namespace.cc:11:3: error: ‘S::S’ names the constructor, not the type
S::S::S var;
^
namespace.cc:11:11: error: expected ‘;’ before ‘var’
S::S::S var;
^
namespace.cc:11:14: error: statement cannot resolve address of overloaded function
S::S::S var;
^
哪种编译器是对的,为什么?究竟 的规则是什么&#34;过度合格&#34;名字?
答案 0 :(得分:3)
指定的初始值设定项是c++2a中C ++的C功能。它们是C ++模式中的常见扩展。显然,此时它们仅限于pod(类C)类型。他们没有惊喜。
通常,不同的编译器会因错误的代码而产生不同的错误,尤其是在使用C ++扩展时。 C ++标准从不强制要求诊断内容(可能有例外,但我不记得是什么)。
gcc有一个扩展名,可以让你命名对象构造函数。这与您对struct命名空间的病态使用相矛盾。
答案 1 :(得分:3)
Yakk已经解决了您问题的指定初始化部分。我将解答你问题的最后部分。 function query($_query, $_params = array()) {
global $_DB; # <- Database connection object
$query = $_DB->prepare($_query);
if (! $query)
echo $_DB->errorInfo();
try {
$query->execute($_params);
} catch (PDOException $e) {
die( $e->getMessage() );
}
return $query;
}
(在此上下文中)是否有效?不,按class.qual#2:
在查找中,函数名称不被忽略 34 和 nested-name-specifier指定一个C类:
如果在C中查找,在嵌套名称说明符之后指定的名称是C(Clause [class])的注入类名,或
在using声明的using声明符中,是一个成员声明,如果在之后指定的名称 nested-name-specifier与标识符或 simple-template-id在模板的最后一个组件中的模板名称 嵌套名称说明符,
该名称被认为是为C类的构造函数命名。
为了使其有效,您需要明确说出S::S::S var
。所以clang 3.9错了。
此外,Rob的评论与此无关。在类定义中查找时,struct S::S::S var
只是一个注入的类名。