以下代码是否会调用未定义的行为?
std::variant<A,B> v = ...;
std::visit([&v](auto& e){
if constexpr (std::is_same_v<std::remove_reference_t<decltype(e)>,A>)
e.some_modifying_operation_on_A();
else {
int i = e.some_accessor_of_B();
v = some_function_returning_A(i);
}
}, v);
Run Code Online (Sandbox Code Playgroud)
特别是,当变体不包含时A,此代码将重新分配,A同时仍保留对先前持有的type对象的引用B。但是,由于分配后不再使用该引用,因此我觉得代码很好。但是,标准库是否可以以std::visit
上述方式不确定的方式自由实施?
#include <iostream>
template <class U, class T>
void foo(U&, T&)
{
std::cout << "first";
}
template <class T>
void foo(int&, const T&)
{
std::cout << "second";
}
int main()
{
int a;
double g = 2.;
foo(a, g); // prints "first"
return 0;
}
Run Code Online (Sandbox Code Playgroud)
要调用第二个foo重载,编译器只需执行一次模板类型推导,但对于第一次重载,它需要执行两次.你能解释为什么第一次超载被调用了吗?
考虑以下:
struct A {
A(int, int) { }
};
struct B {
B(A ) { } // (1)
explicit B(int, int ) { } // (2)
};
int main() {
B paren({1, 2}); // (3)
B brace{1, 2}; // (4)
}
Run Code Online (Sandbox Code Playgroud)
建设brace中(4)清楚明确地调用(2).在铛,施工paren中(3)明确要求(1),其中作为GCC 5.2,它失败编译:
main.cpp: In function 'int main()':
main.cpp:11:19: error: call of overloaded 'B(<brace-enclosed initializer list>)' is ambiguous
B paren({1, 2});
^
main.cpp:6:5: note: candidate: B::B(A)
B(A ) …Run Code Online (Sandbox Code Playgroud) 给定一些可流式的类型:
struct X {
int i;
friend std::ostream& operator<<(std::ostream& os, X const& x) {
return os << "X(" << x.i << ')';
}
};
Run Code Online (Sandbox Code Playgroud)
我想把它添加到一个std::string.我可以这样实现:
void append(std::string& s, X const& x) {
std::ostringstream os;
os << x;
s.append(os.str());
}
Run Code Online (Sandbox Code Playgroud)
但这似乎很蹩脚,因为我正在将数据写入一个流,然后为了将其附加到另一个流上而分配一个新的字符串.有更直接的路线吗?
考虑这个函数:
std::vector<unsigned> copy(std::vector<unsigned> const& v) noexcept
{ return v; }
int main()
{
try {
(void)copy({1, 2, 3});
} catch(...) {}
}
Run Code Online (Sandbox Code Playgroud)
返回对象的副本构造可能会抛出。在这种情况下,异常是否会传播给调用者(即它被认为发生在main),从而在处理catch(...)程序中进行处理?或者异常会遇到noexcept并导致调用std::terminate()?
C++17/C++20 中关于生命周期规则的变化(标准化 RVO、临时物化、隐式对象创建等)是否相对于标准的先前版本改变了这方面的一些规则?
考虑以下简单(在模板问题的范围内)示例:
#include <iostream>
template <typename T>
struct identity;
template <>
struct identity<int> {
using type = int;
};
template<typename T> void bar(T, T ) { std::cout << "a\n"; }
template<typename T> void bar(T, typename identity<T>::type) { std::cout << "b\n"; }
int main ()
{
bar(0, 0);
}
Run Code Online (Sandbox Code Playgroud)
clang和gcc都在那里打印"a".根据[temp.deduct.partial]和[temp.func.order]中的规则,为了确定部分排序,我们需要合成一些独特的类型.所以我们有两次尝试扣除:
+---+-------------------------------+-------------------------------------------+
| | Parameters | Arguments |
+---+-------------------------------+-------------------------------------------+
| a | T, typename identity<T>::type | UniqueA, UniqueA |
| b | T, T | UniqueB, typename identity<UniqueB>::type |
+---+-------------------------------+-------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
c++ templates partial-ordering language-lawyer overload-resolution
在我的理解中,存在的唯一理由std::make_pair,并std::make_tuple是,你不必自己写的类型,它们会自动推导.在C++ 1z中,我们对类模板进行了模板参数推导,这使我们可以简单地编写
std::pair p(1, 2.5); // C++1z
Run Code Online (Sandbox Code Playgroud)
代替
auto p = std::make_pair(1, 2.5); // C++11/14
Run Code Online (Sandbox Code Playgroud)
情况std::tuple类似.这导致以下问题:在C++ 1Z,有一种情况,其有利于使用std::make_pair和std::make_tuple替代使用的构造std::pair和std::tuple?
请考虑纯C++ 1z代码(即不需要向后兼容C++ 14)并假设每个人都熟悉这个C++ 1z特性.
Herb Sutter在他的"宇宙飞船"运营商提案(第12.2节,第12页底部)中说:
基于所有内容
<=>及其返回类型:此模型具有主要优势,与先前的C++提议和其他语言的功能相比,此提案有一些独特之处:[...]
(6)效率,包括最终实现用于比较的零开销抽象:绝大多数比较总是单通道.唯一的例外是生成,
<=并且>=在支持部分排序和相等的类型的情况下.对于<单通是基本实现了零开销的原则,以避免重复平等的比较,如struct Employee { string name; /*more members*/ };在使用的struct Outer { Employeee; /*more members*/ };-今天的对比违反零开销抽象,因为operator<在Outer执行冗余相等比较,因为它执行if (e != that.e) return e < that.e;横贯平等前缀e.name两次(如果名称相同,则遍历Employee两次其他成员的相等前缀),这通常无法优化.正如Kamiński所指出的,零开销抽象是C++的支柱,并且首次实现它的比较是这种设计的一个重要优势<=>.
但他给出了这个例子(第1.4.5节,第6页):
class PersonInFamilyTree { // ...
public:
std::partial_ordering operator<=>(const PersonInFamilyTree& that) const {
if (this->is_the_same_person_as ( that)) return partial_ordering::equivalent;
if (this->is_transitive_child_of( that)) return partial_ordering::less;
if (that. …Run Code Online (Sandbox Code Playgroud) 大卫霍尔曼最近在推特上发布了以下示例(我稍微减少了):
struct FooBeforeBase {
double d;
bool b[4];
};
struct FooBefore : FooBeforeBase {
float value;
};
static_assert(sizeof(FooBefore) > 16);
//----------------------------------------------------
struct FooAfterBase {
protected:
double d;
public:
bool b[4];
};
struct FooAfter : FooAfterBase {
float value;
};
static_assert(sizeof(FooAfter) == 16);
Run Code Online (Sandbox Code Playgroud)
您可以检查godbolt上的clang中的布局,并查看大小更改的原因是,FooBefore成员value放置在偏移16处(保持完全对齐8 FooBeforeBase)而在FooAfter,成员value放置在偏移12处(有效地使用FooAfterBase的尾巴填充).
我很清楚这FooBeforeBase是标准布局,但FooAfterBase不是(因为它的非静态数据成员并不都具有相同的访问控制,[class.prop]/3).但是FooBeforeBase,标准布局需要这方面的填充字节是什么呢?
gcc和clang都重用了FooAfterBase填充,最后用了sizeof(FooAfter) == 16.但是MSVC没有,结果是24.每个标准是否有必要的布局,如果没有,为什么gcc和clang做他们做的事情?
有一些混乱,所以只是为了清理:
FooBeforeBase 是标准布局FooBefore是 …我正在查看 n4713 C++ 标准中的 8.4.4.1:
void f() {
float x, &r = x;
[=] {
decltype(x) y1; // y1 has type float
decltype((x)) y2 = y1; // y2 has type float const& because this lambda is not mutable and x is an lvalue
decltype(r) r1 = y1; // r1 has type float&
decltype((r)) r2 = y2; // r2 has type float const&
};
}
Run Code Online (Sandbox Code Playgroud)
标准说 r2 有 type float const&,然后我尝试打印出类型:
#include <iostream>
template <class T>
void print_type() {
std::cout …Run Code Online (Sandbox Code Playgroud)