这个问题是指在最新的C++20草案中增加了P0593。
这是我的例子:
#include <cstdlib>
#include <cstdio>
void foo(void *p)
{
if ( std::getchar() == 'i' )
{
*(int *)p = 2;
std::printf("%d\n", *(int *)p);
}
else
{
*(float *)p = 2;
std::printf("%f\n", *(float *)p);
}
}
int main()
{
void *a = std::malloc( sizeof(int) + sizeof(float) );
if ( !a ) return EXIT_FAILURE;
foo(a);
// foo(a); [2]
}
Run Code Online (Sandbox Code Playgroud)
此代码是否针对最新草案下的所有输入进行了明确定义?
P0593 中表达的基本原理非常清楚[2]
,如果两个用户输入项不同,取消注释将导致由于严格的别名违规而导致未定义的行为。隐式对象创建应该只发生一次,在malloc
; 它不是由foo
.
对于程序的任何实际运行,都存在一个未指定的隐式对象集的成员,可以使程序定义良好。但是我不清楚 [intro.object]/10 中提到的隐式对象创建的选择是否必须在malloc
发生时进行;或者决定是否可以“时间旅行”。
对于将二进制 blob 读入缓冲区然后做出如何访问它的运行时决定(例如反序列化;并且标头告诉我们是浮点数还是整数即将出现)的程序,可能会出现同样的问题。
为了在 C++20 中使用自编模块提出问题或演示错误/功能,能够使用Matt Godbolt 的编译器资源管理器会很棒。
例子:
test.cpp(模块测试):
export module test;
export template<typename T>
void do_something(const T&)
{
}
Run Code Online (Sandbox Code Playgroud)
编译 clang++ -std=c++20 -stdlib=libc++ -fmodules -c -Xclang -emit-module-interface -o test.pcm test.cpp
主.cpp:
import test;
int main() {
do_something(7);
}
Run Code Online (Sandbox Code Playgroud)
编译 clang++ -std=c++20 -stdlib=libc++ -fmodules -fimplicit-modules -fimplicit-module-maps -fprebuilt-module-path=. main.cpp
问:有没有办法用编译器资源管理器来做到这一点?
我在浏览cppreference 时看到vector
C++20 中删除了它的比较操作,并<=>
引入了飞船运算符 ( )。对于许多其他标准库容器,如set
和 ,可以看到同样的事情map
。
如何在新标准中进行比较?另外,C++20 会开始在旧代码上出错吗?
在一个相关的问题(“ std::string 格式,如 sprintf ”)中,我了解了这个很棒的新 C++20 标头<format>。
但是,似乎没有支持 compiler。这是正确的还是有办法使用它?
我正在使用带有-std=c++2a
标志的g++ 9.3,但<format>
无法识别库。
#include <format> // fatal error: format: No such file or directory
#include <iostream>
int main(){
std::cout << std::format("Hello {}!", "World");
}
Run Code Online (Sandbox Code Playgroud)
g++-9 test.cpp -o test -std=c++2a
我想摆脱enable_if
模板中的所有邪恶s 并用 C++20 概念替换它们,但是几乎没有关于概念的任何信息,并且几乎我阅读的任何来源的语法都发生了变化。
这是一个函数,它接受任何带有MyClass
值的容器的两个迭代器:
template <class IteratorType, typename = std::enable_if<std::is_same<
typename std::iterator_traits<IteratorType>::value_type,
MyClass
>::value, void>>
void myFunction( IteratorType begin, IteratorType end ) {}
Run Code Online (Sandbox Code Playgroud)
我知道可以使用概念转换此功能,但我找不到好的线索开始。
这是来自 C++20 规范 ( [basic.life]/8 )的代码示例:
struct C {
int i;
void f();
const C& operator=( const C& );
};
const C& C::operator=( const C& other) {
if ( this != &other ) {
this->~C(); // lifetime of *this ends
new (this) C(other); // new object of type C created
f(); // well-defined
}
return *this;
}
int main() {
C c1;
C c2;
c1 = c2; // well-defined
c1.f(); // well-defined; c1 refers to a new object of type …
Run Code Online (Sandbox Code Playgroud) std::begin
和 new 和有什么不一样std::ranges::begin
?(同样为end
,size
等等)
两者似乎工作相同:
#include <iostream>
#include <vector>
#include <array>
#include <ranges>
template<std::ranges::range R>
void printInfo(const R &range)
{
std::cout << (std::ranges::begin(range) == std::begin(range));
}
template<class T>
struct X
{
std::vector<T> v;
auto begin() const { return v.begin(); }
auto end() const { return v.end(); }
};
int main()
{
printInfo(std::vector{1, 2, 3, 4});
printInfo(std::array{1, 2, 3, 4});
printInfo(X<int>{{1, 2, 3, 4}});
int oldSchool[]{1, 2, 3, 4};
printInfo(oldSchool);
}
Run Code Online (Sandbox Code Playgroud)
1111
按预期编译和打印。
难道ranges::begin …
从 libstdc++<concepts>
头文件:
namespace ranges
{
namespace __cust_swap
{
template<typename _Tp> void swap(_Tp&, _Tp&) = delete;
Run Code Online (Sandbox Code Playgroud)
从 MS-STL<concepts>
标头:
namespace ranges {
namespace _Swap {
template <class _Ty>
void swap(_Ty&, _Ty&) = delete;
Run Code Online (Sandbox Code Playgroud)
我从未遇到过= delete;
要禁止调用复制/移动赋值/ctor 的上下文之外的情况。
我很好奇这是否有必要,所以我= delete;
像这样注释了库中的部分:
// template<typename _Tp> void swap(_Tp&, _Tp&) = delete;
Run Code Online (Sandbox Code Playgroud)
看看下面的测试用例是否编译。
#include <concepts>
#include <iostream>
struct dummy {
friend void swap(dummy& a, dummy& b) {
std::cout << "ADL" << std::endl;
}
};
int main()
{
int a{};
int …
Run Code Online (Sandbox Code Playgroud) I would expect that in C++20 the following code prints nothing between prints of A and B (since I expect guaranteed RVO to kick in). But output is:
A
Bye
B
C
Bye
Bye
So presumably one temporary is being created.
#include <iostream>
#include <tuple>
struct INeedElision{
int i;
~INeedElision(){
std::cout << "Bye\n";
}
};
std::tuple<int, INeedElision> f(){
int i = 47;
return {i, {47}};
}
INeedElision g(){
return {};
}
int main()
{
std::cout << "A\n";
auto x = …
Run Code Online (Sandbox Code Playgroud) 在 C++20 的最终工作草案(以及下面链接的最新公开可用草案)中,关于如何允许对象替换其他对象,[basic.life] 的措辞已经改变,以便指针、引用和对象的name 自动引用新对象。为此,引入了“透明可替换”的关系。但是,我不确定我是否正确理解了这一点。考虑这个例子:
struct X {int a = 3; float b;};
X x;
new(&x.a) int(5);
x.a == 5 // true without std::launder?
Run Code Online (Sandbox Code Playgroud)
在 C++17 中这当然是正确的,因为旧的 int 既不是 const 对象,也不是具有 const 非静态成员的类。
然而,现在新的透明可替换关系可能不再允许这样做了。在考虑新旧 int 对象的关系时,满足条件(8.1)到(8.4),但条件(8.5)呢?
o1 (旧的 int)和 o2 (新的 int)都是完整的对象(旧的 int 肯定是一个子对象,所以这部分是假的)或者 o1 和 o2 分别是对象 p1 和 p2 的直接子对象,而 p1可以透明地替换为 p2。
new int 是一个完整的对象,因为它是“自己”构造的(我们只放置了一个 new int 而不是一个新的 X)?
或者是否可以认为由于[intro.object]\2的措辞,新 int 是 x 的子对象,就像旧 int 一样,(我高度怀疑这是预期的解释,tbh),因此 x 满足p1 和 p2 …
c++ ×10
c++20 ×10
c++-concepts ×1
c++-modules ×1
copy-elision ×1
enable-if ×1
formatting ×1
g++ ×1
header-files ×1
range ×1
rvo ×1
sfinae ×1
std-ranges ×1
stdlaunder ×1
stdtuple ×1
stl ×1