小编Dai*_*ner的帖子

为什么成员函数不能要求同一类的 static constexpr 成员为 true?

我尝试让成员函数要求静态 constexpr 布尔成员为 true。这对于 DRY 一个相当复杂的需求非常有帮助。我不知道编译器不允许我这样做的原因。

要求稍微不那么复杂的最小示例:

template <typename T>
struct Foo
{
    static constexpr bool isInt = std::integral<T>;
    void bar() requires (isInt);
    void goo() requires std::integral<T>;
};

template <typename T>
void Foo<T>::bar() requires (Foo<T>::isInt) // error: out-of-line definition of 'bar' does not match any declaration in 'Foo<T>' x86-64 clang 14.0.0 #1
{
    // ...
}

template <typename T>
void Foo<T>::goo() requires std::integral<T> // ok
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这是因为isInt是在同一个类中声明的吗?或者我有某种语法错误?

c++ constexpr c++20 requires-clause

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

将可变参数模板整数转换为 switch 语句

我想做以下事情:

// function that depends on key to do stuff
template <int key>
void bar()  {...}

template <int ...Keys>
void foo(int key) {
   // WHAT SHOULD BE HERE?
}

std::cin >> key;
foo<1,3,5,7,9>(key);
Run Code Online (Sandbox Code Playgroud)

使得它变成

template <int ...Key>
void foo(int key) {
  switch (key) {
      case 1: bar<1>();break;
      case 3: bar<3>();break;
      case 5: bar<5>();break;
      case 7: bar<7>();break;
      case 9: bar<9>();break;
      default: break;
  }
}
Run Code Online (Sandbox Code Playgroud)

如何生成一个 switch 语句,将所有可变参数模板参数枚举为高效的 switch 语句,而无需手动编写 switch 语句?

c++ templates variadic-templates c++17

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

如何通过范围解析访问未命名的名称空间?

我有这个:

#include <iostream>
using namespace std;

// Variable created inside namespace
namespace first
{
    int val = 500;
}

namespace
{
    int val = 400;
}

// Global variable
//int val = 100;

int main()
{
    // Local variable
    int val = 200;

    // These variables can be accessed from
    // outside the namespace using the scope
    // operator ::
    cout << first::val << '\n'; 
    cout << ::val << '\n'; 
    cout << val << '\n'; 

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

在这种情况::val …

c++ global unnamed-namespace

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

lambda 捕获中的 f = std::forward 是什么意思?

我有以下代码,用于调用对象上的函数并以完美转发方式传递任何参数

template <typename F, typename T>
inline auto call_with_args(F&& f, T&& t) {
    return [f = std::forward<F>(f), t = std::forward<T>(t)]
    (auto&&... args) mutable { return (t.*f)(std::forward<decltype(args)>(args)...); };
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试阅读此内容,但我不确定它的[f = std::forward<F>(f)]作用是什么。这就是“按值捕获”语法,但这有什么关系std::forward(这是我能读到的到右值引用的转换)?是否f使用新变量重新定义,该变量在通用引用绑定到函数参数后被分配任何类型值类别?ff

有人可以用简单的语言向我解释一下吗?

c++ lambda metaprogramming perfect-forwarding forwarding-reference

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

为什么关联容器具有非常量迭代器参数的擦除重载?

C++11 更改std::vector::erase为采用 aconst_iterator而不是iterator. 同样的事情也适用于std::dequeand std::list,而std::forward_listC++11 中的 witherase_after也采用const_iterator.

相比之下,std::set::erase保留了它的iterator重载,而 C++11 只是添加了一个const_iterator。同样的事情也适用于所有关联容器:std::mapstd::multisetstd::multimapall 保留了 C++11 之前的iterator重载std::unordered_setstd::unordered_map而 、std::unordered_multiset、 和std::unordered_multimapall 则通过iteratorconst_iterator重载引入。

事实上,对于所有四个集合类,iteratorconst_iterator很可能是同一类型

那么为什么会出现这种差异呢?除了与非关联容器不一致之外,还与范围擦除重载不一致,这些重载都在 C++11 中更改为采用一对const_iterators 而不是一对iterators。由于 aniterator必须可转换为 a const_iterator,因此无需将所有四种可能的参数组合用于范围擦除。同样,单值擦除不需要“所有两种组合”,那么为什么要保留重载呢iterator

c++ iterator stl erase c++11

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

std::map 尝试 emplace 与 emplace 奇怪的行为

常见的建议是在几乎所有情况下都优先std::map::try_emplace使用std::map::emplace

我编写了一个简单的测试来跟踪调用这些函数时的对象创建/复制/移动/销毁,无论是否发生冲突,结果表明,try_emplace当密钥尚未在地图中时,会产生额外的移动和销毁密钥。

为什么行为上有差异?

我确实知道移出对象的移动和销毁通常很便宜,尤其是对于琐碎的键来说,但我仍然对结果感到惊讶,因为它们似乎暗示在某些情况下可能会emplace更有效。

编译器资源管理器链接(Clang 14、libc++、-O3)

来源:

#include <map>
#include <iostream>

struct F {
    F(int i): i(i) { std::cout << "- ctor (" << i << ")\n"; }
    ~F() { std::cout << "- dtor (" << i << ")\n"; }
    F(const F& f): i(f.i) { std::cout << "- copy ctor (" << i << ")\n"; }
    F(F&& f): i(f.i) { std::cout << "- move ctor (" << i << ")\n"; } …
Run Code Online (Sandbox Code Playgroud)

c++ stdmap emplace

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

为什么当删除复制或移动构造函数时,命名返回值优化的 C++ 编译会失败?

我在 C++ 11/17/20/23 上的 C++ 上的 gcc 13.1 上尝试了以下操作,但是当删除移动或复制构造函数时,它无法编译。

如果未删除这些构造函数,则命名返回值优化将起作用,并且复制/移动都不会完成。

有趣的是,如果我删除名称并直接返回纯右值,那么简单的返回值优化就会起作用。

谁能对此提供解释?

#include <memory>
#include <iostream>

struct Foo{
    Foo(int v): a{v} { std::cout << "Create!\n"; }
    ~Foo() { std::cout << "Destruct!\n"; }


    Foo(const Foo&)=delete;
    Foo(Foo&&)=delete;
    
    int a;
};

// I DON'T WORK!
Foo makeFoo() {
    Foo foo{5};
    return foo;
}

// I WORK!
//Foo makeFoo() {
//    return Foo{5};
//}

int main() {
    auto foo = makeFoo();
    std::cout << "Hello world! " << foo.a << "\n";
}
Run Code Online (Sandbox Code Playgroud)

c++ return-value-optimization c++17 c++20

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

模板化非类型模板参数的推导

f编译器是否应该能够推断出默认为的函数模板的非类型模板参数的类型n{}?C++20 标准中的哪个具体规则允许/强制执行此操作?

template<typename = int>
struct s {
    template<typename = int>
    struct n {};

    template<n = n{}>
    constexpr int f();
};
static_assert(requires { s{}.f(); }); // clang ok, gcc ok, msvc nope
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,MSVC由于某种原因接受以下代码,而其他编译器甚至不允许该语法。难道MSVC只是和它想象中的朋友在这里开个茶会吗?f并且,除了将 fromn的NTTP 类型更改为 之外,是否有适用于所有 3 个编译器的解决方法auto

template<typename = int>
struct s {
    template<typename = int>
    struct n {};

    template<n<typename> = n{}>
    constexpr int f();
};
static_assert(requires { s{}.f(); }); // clang nope, gcc nope, msvc …
Run Code Online (Sandbox Code Playgroud)

c++ templates type-deduction c++20

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

如何在C++中仅将成员变量转换为字节数组?

长话短说

我有一个不仅仅是成员变量(例如它们包含函数)的结构,我只想将成员变量转换为字节数组(/向量),这样我就可以将数据上传到Vulkan中的显卡。如何仅获取结构体中代表成员变量的部分?

我的具体做法

我有一个设置,我使用一个空ParamsBase结构,并从中继承ParamsAParamsB...实际包含成员变量的结构。我使用它,这样我就可以将成员保留ParamsBase在一个Container类中,而无需实际了解具体实现。

我想将类中的 Params 实例转换Container为字节缓冲区。

ParamsA由于我需要实际/ /... 结构的大小ParamsB,因此在创建实例时我使用了一个通用子类,该子类允许我使用单个getSize()函数,而不是在每个 substruct 中覆盖它

// =============================
// === Define Params structs ===
// =============================
struct ParamsBase
{
    virtual size_t getSize() const noexcept = 0;
};

struct ParamsA : public ParamsBase
{
    float vec[3] = { 2.3f, 3.4f, 4.5f };
};

// ===============================================================
// === enable sizeof query for derived structs from ParamsBase === …
Run Code Online (Sandbox Code Playgroud)

c++ struct sizeof

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

是否可以在多次保存相同类型的变体上使用 std::visit ?

例如,我尝试使用 实现 AST std::variant,其中 Token 可以是数字、关键字或变量。其中数字由 表示int,关键字和变量由 表示std::string

enum TokenType : std::size_t {
    Number = 0, Keyword = 1, Variable = 2,
};
using Token = std::variant<int, std::string, std::string>;
Token token(std::in_place_index<TokenType::Variable>, "x");
Run Code Online (Sandbox Code Playgroud)

当我想用 做某事时token,我可以首先确定它的类型token.index(),然后决定要做什么:

switch (token.index()) {
case TokenType::Number:
    return do_sth_with_number(std::get<TokenType::Number>(token));
case TokenType::Keyword:
    return do_sth_with_keyword(std::get<TokenType::Keyword>(token));
case TokenType::Variable:
    return do_sth_with_variable(std::get<TokenType::Variable>(token));
}
Run Code Online (Sandbox Code Playgroud)

不过,我不知道是否可以使用它std::visit来达到同样的效果。我只知道它可以根据变体中的数据类型调用特定函数,但我不知道是否可以根据索引来执行此操作。

我知道我可以通过将关键字和变量包装在两个不同的类中来实现我的目标,但我想知道是否有更好的方法来做到这一点,因为据我了解,在变体中,决定使用哪个函数应该更直接基于索引而不是类型使用。

c++ stl c++17 std-variant

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