小编Jan*_*tke的帖子

何时使用 std::expected 而不是异常

我什么时候应该使用std::expected异常?什么时候应该使用异常?以这个函数为例:

int parse_int(std::string_view str) {
    if (str.empty()) {
        throw std::invalid_argument("string must not be empty");
    }
    /* ... */
    if (/* result too large */) {
        throw std::out_of_range("value exceeds maximum for int");
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

我想在使用此函数时区分不同的错误,因此抛出不同类型的异常很有用。但是,我也可以这样做std::expected

enum class parse_error {
    empty_string,
    invalid_format,
    out_of_range
};

std::expected<int, parse_error> parse_int(std::string_view str) noexcept {
    if (str.empty()) {
        return std::unexpected(parse_error::empty_string);
    }
    /* ... */
    if (/* result too large */) {
        return std::unexpected(parse_error::out_of_range);
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

是否有任何理由使用std::expected异常(性能、代码大小、编译速度、ABI),或者只是风格偏好?

c++ error-handling exception c++23 std-expected

8
推荐指数
0
解决办法
697
查看次数

std::enable_if 和 std::enable_if_t 有什么区别?

C++-14 引入std::enable_if_t.

它 和 和有什么不一样std::enable_if?使用上有什么优点或者区别吗std::enable_if_t

c++ templates stl enable-if

7
推荐指数
1
解决办法
3606
查看次数

什么操作可以使浮点数离开 [0, 1] 范围?

我经常使用[0, 1] 范围内的floatdouble类型。我知道浮点运算是不精确的,所以我通常会限制我的值,以便在运算之前/之后保证它们在这个范围内。

在某些情况下,我依赖浮点数甚至不是轻微的负值,而是完全是<= 1,因此这是必要的。

例如,在这些功能中的任何一个中是否有必要:

// x and y are guaranteed to be in [0, 1]
float avg(float x, float y) {
    // the average of [0, 1] values should always be in [0, 1]
    return std::clamp<float>((x + y) / 2, 0, 1);
}

float mul(float x, float y) {
    // the product of [0, 1] values should always be in [0, 1]
    return std::clamp<float>(x * y, 0, 1);
}

float pow(float x, …
Run Code Online (Sandbox Code Playgroud)

c++ floating-point precision ieee-754

7
推荐指数
1
解决办法
145
查看次数

为什么 std::is_constructible 对于普通聚合类型不成立?

关于C++17;GCC、Clang 和 MSVC 认为简单类类型不能由其任何数据成员类型构造。自 C++20 起,GCC 和 MSVC 改变了这一点,允许编译下面的示例。

#include <type_traits>

struct t {
    int a;
};

static_assert(std::is_constructible<t, int>{});
Run Code Online (Sandbox Code Playgroud)

不幸的是,Clang 在编译时似乎不同意并拒绝这段代码-std=c++20。这是 Clang 的编译器错误吗?为什么所有编译器在编译时t考虑可以使用 an 构造的类型?毕竟,这样似乎很容易构建。int-std=c++17t{0}

c++ language-lawyer aggregate-initialization c++17 c++20

7
推荐指数
1
解决办法
121
查看次数

内联声明变量模板的目的是什么?

C++14 添加了变量模板,它定义了相关变量组。在标准库中,变量模板用于访问每个类型特征的值成员:

template<class T>
inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
Run Code Online (Sandbox Code Playgroud)

C++17 添加了内联变量以更好地支持仅头文件库,这些库可以包含在同一应用程序内的多个源文件中(不同的翻译单元中允许相同的内联变量定义)。但就变量模板而言,无论如何它们都可以在程序中具有多个定义。那么,如果变量模板已经免于 ODR,还有什么理由将它们声明为内联呢?


只要很多人都关注constexpr差异inline constexpr,这是另一个有趣的问题,我就想忽略constexpr这次讨论的目的。

template <typename T>
bool myVar = sizeof(T) > 1;
Run Code Online (Sandbox Code Playgroud)

它与以下内容有何不同:

template <typename T>
inline bool myVar = sizeof(T) > 1;
Run Code Online (Sandbox Code Playgroud)

c++ templates variable-templates c++17 inline-variable

7
推荐指数
1
解决办法
568
查看次数

std::start_lifetime_as() 的实现

在 C++20 中接受P0593R6(“为低级对象操作隐式创建对象”)后,C++23 将得到std::start_lifetime_as()“完成 [P0593R6] 中提出的功能”(参见P2590R2P2679R2cppreference C++ 23 功能测试页)。

参考实现是什么样子std::start_lifetime_as()的?

这样的事情就足够了,还是还有更多?

#include <cstddef>
#include <new>

template<class T>
    T* start_lifetime_as(void* p) noexcept
{
    new (p) std::byte[sizeof(T)];
    return static_cast<T*>(p);
}
Run Code Online (Sandbox Code Playgroud)

c++ lifetime strict-aliasing undefined-behavior c++23

7
推荐指数
2
解决办法
757
查看次数

为什么 std::copy 比 std::string 构造函数更快?

我尝试了这些代码来比较std::copyandstd::string的构造函数。

#include <chrono>
#include <iostream>
#include <vector>

void construct_test() {
  std::vector<uint8_t> raw_data;
  for (int i = 0; i < 1000 * 1024; i++) {
    raw_data.push_back(i % 256);
  }

  auto start = std::chrono::high_resolution_clock::now();
  std::string target_data;
  target_data = std::string(raw_data.begin(), raw_data.end());
  auto finish = std::chrono::high_resolution_clock::now();
  std::cout << "construct: " << std::chrono::duration_cast<std::chrono::microseconds>(finish -
                                                                     start)
                   .count()
            << "us" << std::endl;
}

void copy_test() {
  std::vector<uint8_t> raw_data;
  for (int i = 0; i < 1000 * 1024; i++) {
    raw_data.push_back(i % 256); …
Run Code Online (Sandbox Code Playgroud)

c++ performance std stdstring

7
推荐指数
1
解决办法
185
查看次数

您可以取消引用临时数组吗?

考虑以下代码:

void foo() {
    int arr[1];
    *arr; // OK

    using T = int[1];
    *T{}; // OK for Clang and MSVC
          // GCC error: taking address of temporary array
}
Run Code Online (Sandbox Code Playgroud)

在 Compiler Explorer 中查看实时代码

我的直觉是,这*T{}应该会导致数组到指针的转换,并且间接寻址的格式良好。不过,我对此并不完全确定。

GCC 是对的还是这是一个错误?是故意的,为了防止开发人员犯错误吗?毕竟,您通常不会取消引用数组。这有记录在任何地方吗?

免责声明
CWG Issue 2548已确认“通过数组纯右值的间接寻址现在也无效”。@StoryTeller 的答案是错误的,并通过假设这也适用于 来误解目标类型*T{}的含义,但该表达式不是指针的初始化。

更多讨论请参见编辑问题EDIT 6555

c++ gcc language-lawyer temporary-objects c++20

7
推荐指数
1
解决办法
382
查看次数

为什么在构造函数中调用虚拟方法并绑定虚拟方法然后稍后调用它会产生不同的结果?

这是我的代码片段:

class Base {
  public:

  Base() {
    foo();
    bind();
  }

  virtual void foo() {
    std::cout << "base foo\n";
  }

  void bind() {
    fn = std::bind(&Base::foo, this);
  };

  std::function<void()> fn;
};

class Derived : public Base {
  public:

  void foo() override {
    std::cout << "derived foo\n";
  }

  void bind()  {
  }

  int val;    
};

int main() {
  Base* p = new Derived();
  p->fn();
}
Run Code Online (Sandbox Code Playgroud)

输出是:

class Base {
  public:

  Base() {
    foo();
    bind();
  }

  virtual void foo() {
    std::cout << "base …
Run Code Online (Sandbox Code Playgroud)

c++ constructor virtual-functions stdbind

7
推荐指数
2
解决办法
148
查看次数

如何防止短 lambda 被分成两行?

我有一个关于 C++ lambda 的 clang 格式问题。升级到 Clang-Format 15.0.1 后,我注意到短的但不是在线 lambda 的新行为。下面我将它们称为“双行 lambda”。例子:

单行 lambda

// good/unchanged
auto shortLambda= []() { doSomething(); };
Run Code Online (Sandbox Code Playgroud)

两行 lambda:

// unwanted/new behavior
const auto mediumLambda = [some, args, here](More arguments)
{ return doSomething(some, args, here, arguments); };
Run Code Online (Sandbox Code Playgroud)

多线 Lambda:

// good/unchanged
const auto longLambda= [some, args, here](Are here)
{
   auto result =doSomething(some, args, here, arguments); 
   return result;
};
Run Code Online (Sandbox Code Playgroud)

两行 lambda 的期望行为:

// desired
const auto mediumLambda = [some, args, here](More arguments)
{
   return doSomething(some, args, …
Run Code Online (Sandbox Code Playgroud)

c++ lambda clang-format

7
推荐指数
1
解决办法
109
查看次数