小编Bar*_*rry的帖子

我可以在对std :: visit的调用中更改std :: variant中的保留类型

以下代码是否会调用未定义的行为?

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 上述方式不确定的方式自由实施?

c++ c++17 std-variant

22
推荐指数
1
解决办法
465
查看次数

C++模板函数优先级

#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重载,编译器只需执行一次模板类型推导,但对于第一次重载,它需要执行两次.你能解释为什么第一次超载被调用了吗?

c++ templates function overload-resolution

21
推荐指数
2
解决办法
2181
查看次数

使用braced-init列表调用显式构造函数:是否含糊不清?

考虑以下:

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)

c++ gcc language-lawyer c++11

21
推荐指数
1
解决办法
906
查看次数

将对象直接流入std :: string

给定一些可流式的类型:

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)

但这似乎很蹩脚,因为我正在将数据写入一个流,然后为了将其附加到另一个流上而分配一个新的字符串.有更直接的路线吗?

c++ string

21
推荐指数
1
解决办法
2041
查看次数

标记可能导致构造返回对象异常的函数 `noexcept`

考虑这个函数:

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、临时物化、隐式对象创建等)是否相对于标准的先前版本改变了这方面的一些规则?

c++ exception language-lawyer c++17 c++20

21
推荐指数
1
解决办法
731
查看次数

模板偏序 - 为什么部分演绎在这里成功

考虑以下简单(在模板问题的范围内)示例:

#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)

根据Richard Corden的回答 …

c++ templates partial-ordering language-lawyer overload-resolution

20
推荐指数
2
解决办法
1166
查看次数

在C++ 1z中std :: make_pair和std :: make_tuple的用处

在我的理解中,存在的唯一理由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_pairstd::make_tuple替代使用的构造std::pairstd::tuple

请考虑纯C++ 1z代码(即不需要向后兼容C++ 14)并假设每个人都熟悉这个C++ 1z特性.

c++ c++17

20
推荐指数
1
解决办法
2170
查看次数

三向比较运算符总是有效吗?

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)

c++ operators spaceship-operator c++20

20
推荐指数
3
解决办法
2064
查看次数

标准布局和尾部填充

大卫霍尔曼最近在推特上发布了以下示例(我稍微减少了):

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是 …

c++ g++ language-lawyer standard-layout clang++

20
推荐指数
1
解决办法
595
查看次数

非 const 何时按值捕获引用?

我正在查看 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)

c++ g++ c++17

20
推荐指数
1
解决办法
247
查看次数