奇怪的是,GCC 4.7.2似乎对以下代码没有任何问题:
template<typename T>
T&& identity(T&& x1) {
return std::forward<T>(x1);
}
int main(int, char**) {
int x1 = 1;
int &x2 = identity(x1);
auto f = [&x1]() mutable {
x1 = x1 + 1;
};
auto g1 = [y=x2+1]() {
static_assert(std::is_same<decltype(y), const int>::value, "fail");
std::cout << "g1: " << y << std::endl;
};
auto h1 = [y=identity(x1)+1]() {
static_assert(std::is_same<decltype(y), const int>::value, "fail");
std::cout << "h1: " << y << std::endl;
};
auto g2 = [&y=x2]() {
static_assert(std::is_same<decltype(y), int&>::value, "fail");
std::cout …Run Code Online (Sandbox Code Playgroud) 它是否意味着保证相同的std::type_info::hash_code()值意味着相同的类型?
Cplusplus.com似乎声称:
此函数为任何两个比较相等的type_info对象返回相同的值,而不同的值则返回不同的值.[强调我的]
Cppreference似乎另有说法:
返回一个未指定的值,对于对象,它引用相同的类型.没有给出其他保证,特别是,值可以在同一程序的调用之间改变.[强调我的]
相关标准段落是:
§p18.7.1p7-8
size_t hash_code()const noexcept;
7返回:一个未指定的值,除了在程序的单次执行中,它应为任何两个比较相等的type_info对象返回相同的值.
8备注:实现应为两个不比较相等的type_info对象返回不同的值.[强调我的]
" 应该 "应该在上面的语境中是什么意思?如果段落8是一个要求,那么似乎不可能实现,除非运行时对程序中的所有符号名称进行某种全局统一以确保缺少哈希冲突,这似乎是标准的一个相当大的负担强加于实现,特别是对于一个被调用的函数hash_code().(Itanium实际上需要这个,但它显然是高于标准的额外要求.)
如果" 应该 "并不意味着具有约束力,那么这句话似乎是毫无意义的,也就是标准中的缺陷,因为要求实现尝试满足一个无法依赖的困难要求,不会产生任何价值,只会引起混淆和碎片化.任何人都知道为什么会这样吗?
编辑:也许"缺陷"太强了,但至少它是一个可能混淆的点,应该澄清,因为它显然误导了至少一个参考网站,并传递误导任何依赖它的人.此外,它实际上是可能实现的要求(只要受实现支持的类型的数量比范围更小size_t),如果全球uniquing是在运行时完成,如果标准是试图表明这为目前还不清楚理想的实施策略与否.
这是非常迂腐的但是在C++ 03中,显然不符合程序在命名空间中重载(而不是特殊化)模板函数的程序std:请参阅这里的提及以及对comp.lang.c ++的长期讨论.
即没关系:
namespace std
{
template <>
void swap (Foo & f, Foo & g)
{
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
但这不是(如果我理解正确的话......):
namespace std
{
template <typename T>
void swap (TempateFoo<T> & f, TempateFoo<T> & g)
{
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
这在C++ 11中仍然如此吗?此外,这是否也适用于模板类(如std::hash),或仅适用于模板函数?
编辑:另外,有没有标准库实现的例子,后者会在实践中破坏?如果没有,是否有一个特殊原因可以解除超载问题,就像上面的第二种情况一样?(理论上可能会破坏什么?)
我正在阅读cppreference中的std :: thread文档(并不总是100%准确,我知道),并注意到以下定义为std::thread传递"指向数据成员指针"时的行为(不是"指针指向 - member-function")作为它的第一个参数(f)和所需类的对象作为它的第二个参数(t1在复制到thread-local-storage之后):
如果N == 1并且f是指向类的成员数据对象的指针,则访问它.忽略对象的值.实际上,执行以下代码:t1.*f if和t1的类型是T,引用T或引用从T派生的类型(*t1).*f否则.
现在,我不打算std::thread以这种方式使用,但我对这个定义感到沮丧.显然,唯一发生的事情是访问数据成员并忽略值,这似乎根本就没有任何可观察到的副作用,这意味着(据我所知)它可能也是一个无操作.(我可能会遗漏一些明显的东西......?)
起初,我认为这可能是一个错误打印,并且意味着数据成员被访问然后被调用(因为它可能是一个可调用的对象,即使它不是一个函数)但我在GCC中使用以下代码对其进行了测试-4.7确实没有电话:
#include <iostream>
#include <thread>
struct S
{
void f() {
std::cout << "Calling f()" << std::endl;
}
struct {
void operator()() {
std::cout << "Calling g()" << std::endl;
}
} g;
};
int main(int, char**)
{
S s;
s.f(); // prints "Calling f()"
s.g(); // prints "Calling g()"
std::cout << "----" << std::endl;
auto x = &S::f; …Run Code Online (Sandbox Code Playgroud) 当我回答这个问题时,出现了这个问题:标准是否允许并对friend标准库类和/或函数做出任何保证?
在这种特殊情况下,问题是的情况是:
class MyUserDefinedType
{
friend struct std::default_delete<MyUserDefinedType>;
private:
~MyUserDefinedType() { }
}
Run Code Online (Sandbox Code Playgroud)
保证允许MyUserDefinedType存储在具有默认删除器的对象std::unique_ptr<MyUserDefinedType>或std::shared_ptr<MyUserDefinedType>对象中.
通常,标准库中描述的类是直接实现其功能所必需的,还是可以使用任意级别的间接?例如,是否有可能
std::default_delete<MyUserDefinedType>实际上是using在内部命名空间中定义的类的别名std,在这种情况下,friend声明是非法的要么
std::default_delete<MyUserDefinedType>调用实际执行删除的其他类,在这种情况下,friend声明将没有所需的效果或者其他类似的东西?
我的猜测是,这是UB不能保证工作,但我很好奇,如果这是由标准具体解决.
上面给出的这个具体例子适用于clang trunk(w/libc ++)和GCC 4.7.2(w/libstdc ++),FWIW
我正在阅读Itanium ABI,上面写着
当且仅当指针相等时,两个 type_info 指针才指向等效类型描述。实现必须满足此约束,例如通过使用符号抢占、COMDAT 部分或其他机制。
有谁知道在流行平台(例如使用 GCC 和 GNU binutils 的 Linux)上使用动态加载库时如何在实践中实现这一点的具体细节?它有多可靠?
另外,我的印象是,typeidMSVC 中的比较是(是?)使用对损坏的符号名称进行运行时字符串比较来实现的,因为不能保证满足此要求。现在还是这样吗?是否存在技术平台限制阻止 MSVC 使用与 Itanium ABI 平台上使用的相同技术?
编辑还有一个问题:跨模块边界(在任一 ABI 中)捕获异常是否也依赖于 RTTI 信息,或者除了运行时的等效机制之外是否还涉及另一种机制dynamic_cast?
以下(此处为LiveWorkspace)被GCC 4.7.2,GCC 4.8.0和ICC 13.0.1拒绝.
namespace A {
namespace B {
void C();
}
using B::C;
}
class D {
friend void A::C();
};
Run Code Online (Sandbox Code Playgroud)
此外,它崩溃了Clang 3.2(!).我已经为崩溃错误提交了一个错误报告和补丁,但是我不能100%确定这段代码是否真的错误,因为我在§7.3.3[namespace.udecl]中找不到任何内容或者§11.3[class.friend]明确地解决了这种情况,但也许在我错过的各种名称说明符之一的定义中有一些东西.
此外,似乎所有四个编译器都接受以下(LiveWorkspace在这里):
namespace A {
namespace B {
class C;
}
using B::C;
}
class D {
friend class A::C;
};
Run Code Online (Sandbox Code Playgroud)
这两种情况似乎没有任何根本的不同,所以我很好奇GCC和ICC拒绝第一个例子的理由,但不是这个例子,如果有的话.任何更熟悉标准的人都可以找到解决此问题的任何内容吗?
这绝对是一个小问题,但是因为我正在修补它,我想确定我做的是正确的事情......
新编辑:Johannes的答案解释了为什么我的原始示例被拒绝,但它似乎没有解释为什么GCC和ICC也拒绝以下(LiveWorkspace在这里):
namespace A {
namespace B {
void C();
}
using B::C;
class D { …Run Code Online (Sandbox Code Playgroud)