#include <vector>
int main()
{
std::vector< int > vi;
// This is legal.
for( std::vector< int >::iterator it = vi.begin(); it != vi.end(); ++it )
{
}
// This is not legal. WHY NOT?
// Compiler knows vi's type, as evident from the c++11 syntax for such loop:
// for( auto it : each vi )
// So why not support :: on objects of known type?
for( vi::iterator it = vi.begin(); it != vi.end(); ++it )
{
}
return …
Run Code Online (Sandbox Code Playgroud) int main() {
struct WorkItem {
int node;
unsigned predecessorIndex = 0;
};
auto x = WorkItem { 0 };
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这段代码可以用 Clang 编译,但不能用 GCC:
source_file.cpp:在函数“int main()”中:
source_file.cpp:9:25: 错误:没有匹配的函数调用'main()::WorkItem::WorkItem()' auto x = WorkItem { 0 }; ^
source_file.cpp:9:25: 注意:候选人是:
source_file.cpp:4:10: 注意:main()::WorkItem::WorkItem() struct WorkItem { ^
source_file.cpp:4:10: 注意:候选人需要 0 个参数,1 个提供
source_file.cpp:4:10: 注意:constexpr main()::WorkItem::WorkItem(const main()::WorkItem&)
source_file.cpp:4:10: 注意:参数 1 从 'int' 到 'const main()::WorkItem&' 没有已知的转换
source_file.cpp:4:10: 注意:constexpr main()::WorkItem::WorkItem(main()::WorkItem&&)
source_file.cpp:4:10: 注意:参数 1 从 'int' 到 'main()::WorkItem&&' 没有已知的转换
或 MSVC:
source_file.cpp(9):错误 C2440:“正在初始化”:无法从“初始化列表”转换为“main::WorkItem” …
特别是在自动调用基类构造函数的上下文中:具有默认值的基类的单个参数构造函数是否与默认构造函数(不带参数的构造函数)以相同的方式(例如,如果未指定,则自动调用)?
struct base {
base(int value = 42) {}
};
struct derived : public base {
derived() {} // automatic call to base::base(int) ?
};
Run Code Online (Sandbox Code Playgroud)
编辑:以下与问题无关,这只是我如何想到的。以下代码甚至不显示我所看到的崩溃。请参阅下面的实际示例。
考虑一下:
#include <sstream>
// C++98, std::ostringstream(ios_base::openmode mode = ios_base::out) available
struct OhNo : public std::ostringstream {
OhNo() {
}
void Crash() const {
this->str();
}
};
// later: OhNo f; f.Crash();
Run Code Online (Sandbox Code Playgroud)
std::ostringstream
(在C ++ 11之前)没有无参构造函数。只有一个具有单个参数和默认值。 上面(是的)确实存在,如果没有可用的自变量构造函数,则会自动调用基类构造函数。OhNo
没有调用它的基类的构造函数。
GCC 5.4.0可以很好地进行编译,但是以后会出现段错误(由于未初始化的基类,这是 另一个问题)。Clang 7.0.0也可以很好地编译,并且可以正常运行代码。
谁是对的?是否需要在此处手动调用基类构造函数? …
c++ default-constructor language-lawyer default-arguments c++98
在 C 标准 fe(我的参考文献特别是 ISO/IEC 9899:2011 (C11))中,§3.6 规定:
3.6
1 字节
大到足以容纳执行环境基本字符集的任何成员的可寻址数据存储单元
2 注 1 可以唯一地表示对象的每个单独字节的地址。
3 注2一个字节由连续的比特序列组成,其数量由实现定义。最不重要的位称为低位;最重要的位称为高位。
为什么呢?我认为一个字节的大小在信息技术中是绝对固定的,正好由 8 位组成。
为什么标准会做出这种看似疯狂的声明?
另外:如果字节大小不固定,假设 64 位系统,我们如何谈论 fe achar
由 8 位和int
32 位(4 字节)组成?
这是一个后续问题:当目标指针不是基类的类型时,为什么允许 dynamic_cast 为多态类产生空指针?.
C++17 标准dynamic_cast
在§8.2.7 [expr.dynamic.cast]下指定。
§8.2.7 (1) 状态
表达式
dynamic_cast<T>(v)
的结果是将表达式 v 转换为类型 T 的结果。 T 应是指向完整类类型的指针或引用,或“指向 cv void 的指针”。[...]
(2) 指定值类别,(3) 同一类型内的 cv 转换和 (4)nullptr
大小写。[expr.dynamic.cast] 的每个其他段落都与同一类型层次结构中的多态类型相关联。
dynamic_cast
除了在同一类型层次结构中的类型之间进行转换之外,我不知道任何用例。鉴于以下类型:
struct A
{
virtual ~A() = default;
};
struct B : A
{
virtual ~B() = default;
};
Run Code Online (Sandbox Code Playgroud)
A*
可以强制转换为B*
,这可能是最常见的用例dynamic_cast
:
A* ptr = new B;
dynamic_cast<B*>(ptr);
Run Code Online (Sandbox Code Playgroud)
我期望这将编译,因为B
和A
在同一类型层次(B
源自A
)。在定义良好的程序中,类型指针A* …
使用godbolt.org 在线编译器编译以下示例程序时,Clang-9.0.0 和MSVC v19.24 都在标记为(1)和(2)的行报告错误。错误消息说表达式(reinterpret_cast<uintptr_t>(&x), 1)
不计算为常量。但确实如此,不是吗?
另一方面,GCC-9.2 编译这个示例没有错误。
#include <memory>
int x;
enum
{
Value = (reinterpret_cast<uintptr_t>(&x), 1) // (1)
};
template <int N>
struct Test
{
};
Test<(reinterpret_cast<uintptr_t>(&x), 1)> t; // (2)
Run Code Online (Sandbox Code Playgroud)
问题是:(reinterpret_cast<uintptr_t>(&x), 1)
求值为常数吗?
编译器是否保证评估环境constexpr
中"tautologies"
(例如始终true
或false
分别)的布尔表达式constexpr
?
例如,在以下代码片段(在标有 的行(1)
)中,我在constexpr
环境中调用了一个函数,我打算在non-constexpr
传递函数时导致编译时错误。至少我使用的编译器 ( g++-10.0
) 是这样做的,即使它也可以意识到表达式总是true
不计算它。我问这个问题的原因是 - 据我所知 - 在非 constepxr 上下文中,像这样的表达式i >= std::numeric_limits<int>::min()
被优化true
为int i
.
#include <limits>
constexpr int example_function() { return 1;}
constexpr bool compileTimeErrorDesired = example_function() || true; // (1)
Run Code Online (Sandbox Code Playgroud)
如果(1)
保证in 的行为,则可以在 aconcept
中使用它,以执行不同的代码,具体取决于是否可以在编译时评估作为模板参数提供的函数。我实现了一个非常短的 ( 7 lines-of-code
) 示例,它在编译器资源管理器中完全做到了这一点。
如果使用非 constexpr 函数调用,行 (1) …
通过阅读标准,我无法确定以下代码是否违反了 ODR:
// a.h
#ifndef A_HEADER_FILE
#define A_HEADER_FILE
namespace {
int v;
}
inline int get_v() { return v; }
#endif // A_HEADER_FILE
// a.cpp
#include "a.h"
void f() {
int i = get_v();
// ...
}
// b.cpp
#include "a.h"
void g() {
int i = get_v();
// ...
}
Run Code Online (Sandbox Code Playgroud)
(来源:https : //wiki.sei.cmu.edu/confluence/display/cplusplus/DCL59-CPP.+Do+not+define+an+unnamed+namespace+in+a+header+file)
据说,get_v()
在每个翻译单元中引用了不同的变量,因此它违反了ODR
。
这个答案:内联函数和外部链接说内联放松ODR
所以我不确定为什么这仍然是一个错误?
如果这是否ODR
违规,有人可以将我链接到标准中指定的位置吗?
c++ one-definition-rule inline-functions linkage language-lawyer
标准是否保证
--list.begin() == list.end()
总是成立并且它实际上是一个有效的操作?(list
是 的一个实例std::list
)。
至少 MSVC 2019 似乎就是这种情况。
例如,这在以下情况下会很有用:
for ( auto i = list.begin(); i != list.end(); ++i )
{
...
list.erase(i--);
...
}
Run Code Online (Sandbox Code Playgroud)
,即在迭代时删除元素时,因为i
可能是列表的开头。这也需要++list.end() == list.begin()
持有;那个怎么样?
临时对象的实现通常会尽可能延迟,以避免创建不必要的临时对象。
[注3:临时对象具体化:
(2.1) 将引用绑定到纯右值时 ([dcl.init.ref], [expr.type.conv], [expr.dynamic.cast], [expr.static.cast], [expr.const.cast] , [expr.cast]),
(2.2) 对类纯右值 ([expr.ref], [expr.mptr.oper]) 执行成员访问时,
(2.3) 当对数组纯右值 ([conv.array], [expr.sub]) 执行数组到指针的转换或下标时,
(2.4)std?::?initializer_list<T>
从花括号初始化列表([dcl.init.list])初始化类型对象时,
(2.5) 对于某些未计算的操作数 ([expr.typeid], [expr.sizeof]),和
(2.6) 当具有非cv 类型的纯右void
值出现为丢弃值表达式 ([expr.prop]) 时。
— 尾注]