小编Kyl*_*fel的帖子

覆盖[[noreturn]]虚函数

[[noreturn]]属性可以应用于不打算返回的函数.例如:

[[noreturn]] void will_throw() { throw std::runtime_error("bad, bad, bad ...."); }
Run Code Online (Sandbox Code Playgroud)

但我遇到了以下情况(不,我没有设计这个):

class B {
public:
  virtual void f() { throw std::runtime_error(""); }
};

class D : public B {
  void f() override { std::cout << "Hi" << std::endl; }
};
Run Code Online (Sandbox Code Playgroud)

我真的想把属性[[noreturn]]放在B::f()声明上.但是我不清楚派生类中的覆盖会发生什么.从[[noreturn]]函数成功返回会导致未定义的行为,如果重写也继承了该属性,我当然不希望这样.

问题:通过覆盖[[noreturn] virtual void B::f(),我是否继承了该[[noreturn]]属性?

我查看了C++ 14标准,我无法确定属性是否继承.

c++ inheritance c++11 noreturn

22
推荐指数
2
解决办法
711
查看次数

按元素地址排序

我偶然发现了一种情况,库std::vector<T>使用用户提供的比较对象对容器(例如)进行排序。对于一种特定情况,用户实际上不想对容器进行排序,但排序是无条件发生的。

因此,为了尽量避免这种情况,我想尝试使用根据元素地址排序的比较对象。等价地,我们有:

std::vector nums{1, 5, 4};
auto cmp = [](auto& a, auto& b) { return &a < &b; };
std::sort(nums.begin(), nums.end(), cmp);
Run Code Online (Sandbox Code Playgroud)

这是“有效的”,因为std::vector<T>元素以与向量中元素相同的顺序存储在(连续)内存位置中。最终结果是,nums即使在排序之后,向量似乎也没有被改变。

但是,一旦我替换std::vector<T>std::array<T, N>,我就会遇到分段冲突(请参阅https://gcc.godbolt.org/z/9srehdbhG)。

我的第一个想法是我违反了https://en.cppreference.com/w/cpp/algorithm/sort中列出的类型要求:

  • RandomIt必须满足ValueSwappableLegacyRandomAccessIterator的要求。
  • 解除引用的类型必须满足MoveAssignableMoveConstructibleRandomIt的要求。
  • Compare必须满足Compare的要求。

我的假设是元素的地址在整个排序过程中保持稳定 - 这几乎肯定是错误的。

那么,std::sort()我违反了哪些要求/先决条件?

c++ language-lawyer compiler-bug

14
推荐指数
1
解决办法
518
查看次数

C ++ 20合约和未使用的变量

抱歉,如果这已在其他地方讨论过。让我感到沮丧的是,每当我尝试检查调用函数的后置条件时,我常常必须将返回变量修饰为未使用状态,以避免编译器警告:

auto const count [[maybe_unused]] = some_map.erase(some_key);
assert(count == 1);
Run Code Online (Sandbox Code Playgroud)

该属性的原因assert很明确-是一个预处理器宏,如果NDEBUG设置了则扩展为无操作,或者如果NDEBUG未设置则实际计算表达式。在前一种情况下,count在技​​术上不使用,因此出现编译器警告。

随着C ++ 20中引入合同,该count变量是否仍被视为未使用?换句话说,我将能够执行以下操作:

auto const count = some_map.erase(some_key); // no attribute
[[assert: count == 1]];
Run Code Online (Sandbox Code Playgroud)

还是我必须做一些丑陋的事情:

auto const count [[maybe_unused]] = some_map.erase(some_key);
[[assert: count == 1]];
Run Code Online (Sandbox Code Playgroud)

还是这种实现定义的行为?

c++ language-lawyer c++20

11
推荐指数
1
解决办法
211
查看次数

默认构造函数表达式和左值

我和我的 C++ 同事遇到了一个奇怪的结构:

struct A { int i; };
void foo(A const& a);

int main() {
  foo(A() = A{2}); // Legal
}
Run Code Online (Sandbox Code Playgroud)

这个A() = A{2}表达式完全把我们弄糊涂了,因为它似乎正在分配A{2}给一个临时的、默认构造的对象。但是在编译器资源管理器中看到它(https://gcc.godbolt.org/z/2LsfSk)。它似乎是一个法律声明(由 GCC 9 和 Clang 9 支持),如下声明:

struct A { int i; };

int main() {
  A() = A{2};
  auto a = A() = A{3};
}
Run Code Online (Sandbox Code Playgroud)

因此,在某些情况下,它似乎A()是一个左值。还是这里发生了其他事情?希望得到一些解释,最好是对 C++17 标准的引用。


更新:@Brian 发现这是赋值给右值的重复:为什么编译?. 但如果有人能在 C++ 标准中找到合适的参考,我将不胜感激。

c++ rvalue language-lawyer copy-assignment c++17

6
推荐指数
1
解决办法
192
查看次数

头文件中的内联Lambda

这与我所见过的其他问题类似,但是考虑到C ++ 17对内联变量的介绍,值得提出。考虑以下模式:

auto to_ref = [](auto const& ptr) -> decltype(auto) { return *ptr; }

std::vector<std::unique_ptr<Foo>> foo_ptrs = from_somewhere();
for (Foo const& foo : foo_ptrs | transform(to_ref)) {
}
Run Code Online (Sandbox Code Playgroud)

to_ref通用拉姆达是......嗯,通用...所以是有意义的把它放在一个头这样的人不是到处复制它。

我的问题:模板的链接注意事项也适用于通用lambda吗?换句话说,编译器/链接器有责任确保对于具有相同模板参数的给定模板的多个实例化,不违反ODR。我可以依靠相同的行为,还是应该在inline说明符之前添加说明符auto to_ref = ...;

c++ lambda one-definition-rule

2
推荐指数
1
解决办法
131
查看次数

绑定成员函数的指针/引用的禁止语法

假设我有以下内容:

struct A {
  int foo(int bar) const { return bar; }
};
Run Code Online (Sandbox Code Playgroud)

我想指定一个引用“绑定”成员函数的名称(即):

A a;
auto opt1 = a.foo; // Forbidden, instead do something like...
auto opt2 = [&a] (int i) { return a.foo(i); }; // or ...
auto opt3 = std::bind(&A::foo, a, std::placeholders::_1);
Run Code Online (Sandbox Code Playgroud)

然后调用绑定的成员函数就很简单:

assert(opt1(42) == 42); // If 'opt1' were allowed
assert(opt2(42) == 42); 
assert(opt3(42) == 42);
Run Code Online (Sandbox Code Playgroud)

在我看来,opt1这将是实现目标的首选解决方案。opt1但是,该语言禁止通过 via 指定绑定函数。

我的问题纯粹是合法的:C++(20) 标准的哪一部分禁止像这样的构造opt1 我的问题不是为什么,而是在哪里

c++ language-lawyer

2
推荐指数
1
解决办法
107
查看次数