该概念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>逻辑上应该是可比的。但它们不可能,因为这两种不相关的类型之间没有合理的公共引用。
考虑:
#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 拒绝了它,并显示以下错误消息:
Run Code Online (Sandbox Code Playgroud)<source>:7:26: error: argument to 'operator<=>' cannot be narrowed from type 'int' to 'unsigned int' using T = decltype(x <=> f()); ^ 1 error generated.
(现场演示)
如果模板头 ( 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) 注意:这个问题被简要标记为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) 由于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.
关于这个问题的讨论是在这个非常简单的问题的答案下开始的。
\n这个简单的代码具有意外的构造函数重载解析std::basic_string:
#include <string>\n\nint main() {\n std::string s{"some string to test", 2, 3};\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n现在有人期望这会调用这个构造函数:
\nstd::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\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)
基本原理基于此 C++ …
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 版本中为自定义容器编写自定义迭代器吗?
根据 cppreference,std::atomic<T>::notify_one()将通知至少一个正在等待所述原子的线程。这意味着根据标准,它可以解锁多个线程。这与 相反std::condition_variable::notify_one(),后者指定它将解除阻塞(不超过)一个线程。
这种差异从何而来?这不使用相同的底层机制吗?就标准库的实现而言,所有流行的库是否都有机会通过此调用实际解锁多个,或者是否有一些库总是恰好解锁一个?
我在使用 g++-12 时遇到错误,但在 clang++-13 中不会发生该错误。特别是,这段代码:
\nstruct 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}\nRun Code Online (Sandbox Code Playgroud)\n使用 clang++ 编译,但使用 g++ 编译会出现错误:
\nstruct 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++ 。特别是,我了解到我们不能用作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++ 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++ ×10
c++20 ×10
c++-concepts ×3
constexpr ×2
c++17 ×1
notify ×1
std ×1
std-ranges ×1
stdatomic ×1
stdoptional ×1
wait ×1