标签: c++20

`equality_comparable_with` 是否需要要求 `common_reference`?

概念equality_­comparable_with<T, U>旨在声明类型T和 的对象U可以相互比较,如果它们是,则这具有预期的含义。没关系。

但是,这个概念也需要common_reference_t<T&, U&>存在。其主要推动力common_reference及其伴随的功能似乎是启用代理迭代器,有一个地方来表示此类迭代器之间的关系reference以及value_type此类迭代器的关系。

太好了,但是……这与测试 aT和 a 是否U可以相等有什么关系?为什么标准要求这样做T并且U有一个共同的参考关系只是为了让你比较它们相等?

这会产生奇怪的情况,其中很难有两种类型没有合理地具有逻辑可比性的公共引用关系。例如,vector<int>pmr::vector<int>逻辑上应该是可比的。但它们不可能,因为这两种不相关的类型之间没有合理的公共引用。

c++ c++-concepts c++20

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

三路比较和constexpr函数模板:哪个编译器是对的?

考虑:

#include <compare>

template<class=void>
constexpr int f() { return 1; }

unsigned int x;
using T = decltype(x <=> f());
Run Code Online (Sandbox Code Playgroud)

GCC 和 MSVC 接受T. Clang 拒绝了它,并显示以下错误消息:

<source>:7:26: error: argument to 'operator<=>' cannot be narrowed from type 'int' to 'unsigned int'
using T = decltype(x <=> f());
                        ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

现场演示

如果模板头 ( template<class=void>) 被移除,或者如果f在 的声明之前显式或隐式实例化T,则 Clang 接受它。例如,Clang 接受:

#include <compare>

template<class=void>
constexpr int f() { return 1; }

unsigned x; …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer spaceship-operator constexpr c++20

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

如何展平嵌套的 std::optional?

注意:这个问题被简要标记为this的重复,但它不是一个完全重复的,因为我专门询问 std::optionals 。如果您关心一般情况,仍然是一个值得阅读的好问题。

假设我有嵌套的选项,像这样(愚蠢的玩具示例):

struct Person{
    const std::string first_name;
    const std::optional<std::string> middle_name;
    const std::string last_name;
};
struct Form{
    std::optional<Person> person;
};
Run Code Online (Sandbox Code Playgroud)

和这个垃圾邮件功能:

void PrintMiddleName(const std::optional<Form> form){
    if (form.has_value() && form->person.has_value() && form->person->middle_name.has_value()) {
        std::cout << *(*(*form).person).middle_name << std::endl; 
    } else {
        std::cout << "<none>"  << std::endl; 
    }
}
Run Code Online (Sandbox Code Playgroud)

展平此可选检查的最佳方法是什么?我做了这样的东西,它不是可变参数,但我不太关心(membr3如果真的有必要,我可以再添加一个级别(用 重载),除此之外的一切都是糟糕的代码)。

template<typename T, typename M>
auto flatten_opt(const std::optional<T> opt, M membr){
    if (opt.has_value() && (opt.value().*membr).has_value()){
        return std::optional{*((*opt).*membr)};
    }
    return decltype(std::optional{*((*opt).*membr)}){};
}

template<typename T, typename M1, typename M2> …
Run Code Online (Sandbox Code Playgroud)

c++ c++20 stdoptional

19
推荐指数
3
解决办法
888
查看次数

我们真的需要将范围适配器隐式转换为 bool 吗?

由于ranges::view_interface有一个explicit operator bool()函数,这使得大多数 C++20 范围适配器能够转换为bool

https://godbolt.org/z/ccbPrG51c

static_assert(views::iota(0));
static_assert("hello"sv | views::split(' '));
static_assert(views::single(0) | std::views::transform([](auto) { return 0; }));
Run Code Online (Sandbox Code Playgroud)

虽然这看起来很方便,但我们真的需要这个功能吗?原因是传统的STL容器比如std::vector,或者常用的视图比如std::string_view,没有这个转换为 的功能bool,看起来有些不协调。只是调用.empty()ranges::empty直接确定范围是否为空似乎更直观。

此外,这种隐式转换也可能会引起混淆:

static_assert(!views::empty<int>);
Run Code Online (Sandbox Code Playgroud)

那么,为什么ranges::view_interface提供这个operator bool功能呢?有没有实际的用例?

请注意,这可能是一个基于意见的问题,但我想知道view_interface提供operator bool.

c++ c++20 std-ranges

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

为什么 SFINAE 对 std::basic_string 构造函数之一的限制如此之大?

背景

\n

关于这个问题的讨论是在这个非常简单的问题的答案下开始的。

\n

问题

\n

这个简单的代码具有意外的构造函数重载解析std::basic_string

\n
#include <string>\n\nint main() {\n    std::string s{"some string to test", 2, 3};\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在有人期望这会调用这个构造函数:

\n

std::basic_string<CharT,Traits,Allocator>::basic_string - cppreference.com

\n
\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
template<class T> basic_string( const T& t, size_type pos, size_type n, const Allocator& alloc = Allocator() );(自 C++17 起)(11)
template< class T > constexpr basic_string( const T& t, size_type pos, size_type const Allocator& alloc = Allocator() );(自 C++20 起)(11)
\n
\n

基本原理基于此 C++ …

c++ std language-lawyer c++17 c++20

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

使用 C++20 概念为自定义容器创建迭代器

C++20 引入了概念,这是一种对模板函数或类可以采用的类型施加约束的智能方法。

虽然迭代器类别和属性保持不变,但改变的是执行它们的方式:C++17 之前使用标记,C++20 以来使用概念。例如,您可以使用 std::forward_iterator 概念来标记迭代器,而不是使用 std::forward_iterator_tag 标签。

同样的事情也适用于所有迭代器属性。例如,前向迭代器必须是 std::incrementable。这种新机制有助于获得更好的迭代器定义,并使编译器中的错误更具可读性。

这段文字摘自这篇文章: https ://www.internalpointers.com/post/writing-custom-iterators-modern-cpp

但作者并没有升级如何用概念在C++20上制作自定义迭代器的内容,仍然是<= C++17标签版本。

有人可以举例说明如何使用概念功能在 C++20 版本中为自定义容器编写自定义迭代器吗?

c++ c++-concepts c++20

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

std::atomic::notify_one 可以解锁多个线程

根据 cppreference,std::atomic<T>::notify_one()将通知至少一个正在等待所述原子的线程。这意味着根据标准,它可以解锁多个线程。这与 相反std::condition_variable::notify_one(),后者指定它将解除阻塞(不超过)一个线程。

这种差异从何而来?这不使用相同的底层机制吗?就标准库的实现而言,所有流行的库是否都有机会通过此调用实际解锁多个,或者是否有一些库总是恰好解锁一个?

c++ notify wait stdatomic c++20

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

constexpr C++ 错误:在定义之前使用了析构函数

我在使用 g++-12 时遇到错误,但在 clang++-13 中不会发生该错误。特别是,这段代码:

\n
struct A {\n    constexpr virtual ~A() = default;\n    constexpr A() = default;\n};\n\nstruct B : public A {\n    constexpr ~B() = default;\n    constexpr B() = default;\n};\n\nconstexpr int demo(){\n    B *b = new B();\n    delete b;\n    return 2;\n}\n\nint main(){\n    constexpr int demod = demo();\n    return demod;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

使用 clang++ 编译,但使用 g++ 编译会出现错误:

\n
struct A {\n    constexpr virtual ~A() = default;\n    constexpr A() = default;\n};\n\nstruct B : public A {\n    constexpr ~B() = default;\n    constexpr B() …
Run Code Online (Sandbox Code Playgroud)

c++ constexpr c++20

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

std::string&amp; 类型的非类型模板参数可以在 gcc 中编译,但不能在 clang 中编译

我正在使用此处列出的书籍学习 C++ 。特别是,我了解到我们不能用作std::string非类型模板参数。现在,为了进一步明确我对这个主题的概念,我尝试了以下示例,该示例在 gcc 和 msvc 中编译,但在 clang 中不编译。演示

std::string nameOk[] = {"name1", "name2"};
template<std::string &name>
void foo()
{
   
}
int main()
{
    
    foo<nameOk[0]>(); //this compiles in gcc and msvc but not in clang in C++20  
}
Run Code Online (Sandbox Code Playgroud)

我的问题是哪个编译器就在这里(如果有的话)。也就是说,程序是格式良好的还是 IFNDR。

c++ language-lawyer c++20

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

为什么不同的编译器对这些 require 表达式的行为不同?

为什么 C++ 20 中使用 require 表达式的“Oneable”概念的某些实现无法在某些编译器上编译?

// `Oneable` implemented using `requires` with a simple assignment expression

// clang, gcc, and msvc all compile

template <class T>
concept Oneable = requires(T n) { n = 1; };

static_assert(Oneable<int>);
static_assert(!Oneable<int*>);
Run Code Online (Sandbox Code Playgroud)
// `Oneable` implemented using `requires` with an assignment statement inside
// the body of a lambda expression

// clang and msvc compile
// gcc gives a compiler error on instantiating Oneable<T*>

template <class T>
concept Oneable = requires { []() { T …
Run Code Online (Sandbox Code Playgroud)

c++ c++-concepts c++20

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