小编Jan*_*tke的帖子

在参数列表中构造一个对象并将指向该对象内部数据的指针传递给函数安全吗?

下面的 C++ 代码格式正确吗?std::string函数执行完成之前还是之后会被销毁?

void my_function(const char*);

...

my_function(std::string("Something").c_str());
Run Code Online (Sandbox Code Playgroud)

我知道我可以做到my_function("Something"),但我用std::string这种方式来说明我的观点。

c++ string temporary-objects

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

为什么 std::swap<std::array<int,3>> 无法编译?

我想交换两个固定大小的整数数组。

与直觉相反,以下内容无法编译,因为没有swap找到匹配的实例。

#include <array>
#include <utility>

int main()
{
    std::array<int,3> a, b;
    std::swap< std::array<int,3> >( a, b ); 
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我觉得这很令人惊讶。但是,用编译替换交换std::swap(a,b)并且(根据 VSCode)具有签名

inline void std::swap<int, 3UL>(std::array<int, 3UL> &__one, std::array<int, 3UL> &__two)
Run Code Online (Sandbox Code Playgroud)

我也无法理解。

问:这是怎么回事?

c++ swap std

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

std::move 和临时对象的生命周期

有人能解释一下这段代码的执行顺序吗?

struct Foo {
    ~Foo() {
        std::cout << "1";
    }
};
Run Code Online (Sandbox Code Playgroud)
int main() {
    const Foo& bar = Foo();
    const Foo& baz = std::move(Foo());
    std::cout << "2";
}
Run Code Online (Sandbox Code Playgroud)

以下代码打印121.

我明白为什么我在 2 之后得到 1,这是因为对象的生命周期绑定到它执行的代码块,而且我也知道右值可以绑定到左值 const 引用,但是为什么立即调用移动对象的析构函数?这是什么原因呢?这个析构函数到底在哪里被调用?

c++ destructor lifetime move-semantics stdmove

19
推荐指数
2
解决办法
1325
查看次数

删除基类中的移动构造函数不会阻止从函数返回派生类对象

给定基类 A 和派生类 B,A 删除了移动构造函数:

class A {
public: 
  A()  {}
  A(const A&) = default;
  A(A&&) = delete; 
};

class B : public A
{ 
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,由于删除了移动构造函数,以下函数无法编译:

A f() {
  A a;
  return a;
}
Run Code Online (Sandbox Code Playgroud)

但 B 的类似函数不会报告任何错误:

B g() {
  B b;
  return b;
}
Run Code Online (Sandbox Code Playgroud)

这是否意味着B中的移动构造函数没有被删除?我想知道标准中的规则是什么。

c++ inheritance constructor move-semantics

19
推荐指数
2
解决办法
1647
查看次数

如何在编译时检查所有参数是否有足够的“{}”占位符?

std::format有一个(编译时和运行时)格式字符串验证,但此验证中不包括的一件事是是否有足够的{}占位符用于所有参数(过多的参数将被默默忽略)。

我认为这在某些罕见的情况下可能很有用(例如,如果您生成格式字符串),但我不需要它,并且因此我遇到了一些错误。

我可以做些什么来检查这个编译时间吗?可能通过包装std::format我自己的函数。

例子:

#include <format>
#include <iostream>

int main()
{
    std::cout << std::format("{} {}", 1, 2, 3, 4, 5) << '\n'; // Prints `1 2`, no error!
}
Run Code Online (Sandbox Code Playgroud)

注意: std::format 确实有编译时格式字符串验证。他们只是不检查这个具体问题(过多的争论)。

c++ fmt stdformat

19
推荐指数
1
解决办法
301
查看次数

您可以在编译时将 std::vector 转换为 std::array 而不使向量两次吗?

我正在编译时使用计算一些数据std::vector,并希望将结果作为数组返回,以便可以在运行时进一步使用。我在不进行两次计算的情况下设置数组大小时遇到​​问题。

这是我迄今为止所做的事情的简化示例。代码按预期编译并运行。

constexpr auto make_vector() { 
  // complex calculation here
  return std::vector{1, 2, 3}; 
}

constexpr auto make_array() {
  const auto vec = make_vector();
  std::array<int, make_vector().size()> result{};

  std::copy(vec.cbegin(), vec.cend(), result.begin());
  return result;
}

int main() {
  constexpr auto result = make_array(); // std::array<int, 3>{1, 2, 3}
}
Run Code Online (Sandbox Code Playgroud)

我理解为什么不能用于vec.size()数组大小以及为什么make_vector().size()会产生编译时常量。做两次似乎不是正确的方法。

有没有办法避免调用make_vector两次?我在这里错过了一个基本概念吗?

c++ constexpr c++20

19
推荐指数
1
解决办法
1108
查看次数

为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类?

以下代码打印nullptr而不是emptygodbolt 链接):

#include <iostream>

class empty { };

#if 1
void f(std::nullptr_t) {
    std::cout << "nullptr\n";
}
#endif

void f(empty) {
    std::cout << "empty\n";
}

int main() {
    f({});
}
Run Code Online (Sandbox Code Playgroud)

禁用f(nullptr_t)变体会导致empty打印。当两个变体都可用时,C++ 使用什么规则来选择nullptr_t变体?empty

c++ gcc clang nullptr overload-resolution

17
推荐指数
1
解决办法
987
查看次数

在 lambda 中,第二个属性列表有什么作用?

C++23 允许[[...]]lambda 表达式中的属性:

auto lambda = [] [[nodiscard]]
{
    return 42;
};
Run Code Online (Sandbox Code Playgroud)

但是语法有两个属性列表,大致在参数列表之前和之后:

auto lambda = [] [[nodiscard]] () [[deprecated]]
//               (1)~~~~~~~~~~    (2)~~~~~~~~~~~  // (2) seems to have no effect here
{
    return 42;
};
Run Code Online (Sandbox Code Playgroud)

这两个列表适用于不同的事物,但我无法弄清楚第二个列表的用途,以及我可以在此处放置哪些属性。对于我在 (2) 中尝试的任何属性,Clang 警告:'...' attribute cannot be applied to types

标准是这样说的:

[expr.prim.lambda.closure]/6

... attribute-specifier-seq [位于位置 (2)] 属于相应函数调用运算符或运算符模板的类型。

attribute-specifier-seq [位于位置 (1)] 属于相应的函数调用运算符或运算符模板。

“属于相应函数调用运算符的类型”让我感到困惑。我可以在这里放置哪些属性?这是否仅适用于特定于编译器的属性?如果是,这里可以使用哪些非标准属性?

显然,列表 (2) 早在 C++23 之前就已存在(该提案添加了列表 (1))。

c++ syntax lambda c++23 c++-attributes

17
推荐指数
1
解决办法
831
查看次数

为什么静态成员函数在重载解析期间被视为具有隐式对象参数?

在此链接中: 隐式对象参数

在这句话中:

如果任何候选函数是不具有显式对象参数 (C++23 起) 的成员函数(静态或非静态),但不是构造函数,则将其视为具有额外参数(隐式对象参数) ) 表示调用它们的对象,并出现在第一个实际参数之前。

我不明白为什么这里提到静态这个词?隐式对象参数不是指针this(仅存在于非静态函数中)吗?

在此链接中编辑:链接

引用 :

关键字 this 是右值 (C++11 之前) 纯右值 (C++11 起) 表达式,其值是隐式对象参数(调用非静态成员函数的对象)的地址。它可以出现在以下环境中:

c++ member-functions language-lawyer overload-resolution

16
推荐指数
1
解决办法
1064
查看次数

在嵌套模板中,“require”表达式的计算结果为 false,但代码仍会编译

我无法理解requires关键字如何在嵌套模板中工作。

下面的代码可以在最新版本的 MSVC 和 gcc 上编译(分别使用/std:c++latest和)。-std=c++2a

requires在这样的场景中是否会被简单地丢弃?我不应该这样使用它吗?

#include <type_traits>

template <
    template < typename >
    requires (false) // Should not this stop compilation?
    typename Wrapper >
using Test = Wrapper < int >;

template < typename >
struct S
{
};

int main() {
    Test < S > var;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++20 requires-clause

16
推荐指数
1
解决办法
510
查看次数