我什么时候应该使用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++-14 引入std::enable_if_t.
它 和 和有什么不一样std::enable_if?使用上有什么优点或者区别吗std::enable_if_t?
我经常使用[0, 1] 范围内的float或double类型。我知道浮点运算是不精确的,所以我通常会限制我的值,以便在运算之前/之后保证它们在这个范围内。
在某些情况下,我依赖浮点数甚至不是轻微的负值,而是完全是<= 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++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++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++20 中接受P0593R6(“为低级对象操作隐式创建对象”)后,C++23 将得到std::start_lifetime_as()“完成 [P0593R6] 中提出的功能”(参见P2590R2、P2679R2和cppreference 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) 我尝试了这些代码来比较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) 考虑以下代码:
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
这是我的代码片段:
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++ 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++ ×10
c++17 ×2
c++20 ×2
c++23 ×2
templates ×2
clang-format ×1
constructor ×1
enable-if ×1
exception ×1
gcc ×1
ieee-754 ×1
lambda ×1
lifetime ×1
performance ×1
precision ×1
std ×1
std-expected ×1
stdbind ×1
stdstring ×1
stl ×1