我注意到std::ranges::sort无法排序std::vector<bool>:
<source>:6:51: error: no match for call to '(const std::ranges::__sort_fn) (std::vector<bool, std::allocator<bool> >)'
6 | std::ranges::sort(std::vector{false, true, true});
|
Run Code Online (Sandbox Code Playgroud)
这是允许的吗?我们是否需要专门化std::ranges::sortfor std::vector<bool>?是否有关于委员会如何考虑这一点的任何信息?
最近意外发现gcc和msvc接受如下代码(注意template-list中的requires-clause):
#include <vector>
template <template <class> requires true class>
void f() {}
int main() {
f<std::vector>();
}
Run Code Online (Sandbox Code Playgroud)
和 clang拒绝它的语法:
<source>:3:28: error: template template parameter requires 'class' after the parameter list
template <template <class> requires true class>
^
Run Code Online (Sandbox Code Playgroud)
我应该信任哪个编译器?这段代码在语法上有效吗?
一些范围适配器,例如filter_\xc2\xadview,take_\xc2\xadwhile_\xc2\xadview和transform_view使用std::optional\ 的同类copyable-box来存储可调用对象:
template<input_\xc2\xadrange V, copy_\xc2\xadconstructible F>\nclass transform_view : public view_interface<transform_view<V, F>> {\n private:\n V base_ = V();\n copyable-box<F> fun_;\n};\nRun Code Online (Sandbox Code Playgroud)\n这要求可调用对象F为copy_\xc2\xadconstructible,这也阻止我们将捕获仅移动对象的可调用对象传递给transform_view(Godbolt):
#include <ranges>\n#include <memory>\n\nstruct MoveOnlyFun {\n std::unique_ptr<int> x;\n MoveOnlyFun(int x) : x(std::make_unique<int>(x)) { } \n int operator()(int y) const { return *x + y; }\n};\n\nint main() {\n auto r = std::views::iota(0, 5)\n | std::views::transform(MoveOnlyFun(1));\n}\nRun Code Online (Sandbox Code Playgroud)\n既然view不是必需的copy_constructible,为什么我们要求可调用的呢 …
假设我们有一个 s 数组std::pair:
using Particle = std::pair<std::string, double>;
Particle particles[] {{"Electron", 0.511}, {"Muon", 105.66}, {"Tau", 1776.86}};
Run Code Online (Sandbox Code Playgroud)
我们可以使用具有不同投影函数的C++20范围算法来根据不同的数据成员对它们进行排序:
ranges::sort(particles, {}, &Particle::first);
ranges::sort(particles, {}, &Particle::second);
Run Code Online (Sandbox Code Playgroud)
这看起来非常干净。但是当我将Particle的数据类型移至std::tuple:
using Particle = std::tuple<std::string, double>;
Run Code Online (Sandbox Code Playgroud)
我不能再使用相同的投影度量,因为std::tuple没有first或second没有成员。或者,只需传递 lambda 即可正常工作:
ranges::sort(particles, {}, [](const auto& t) { return std::get<0>(t); });
ranges::sort(particles, {}, [](const auto& t) { return std::get<1>(t); });
Run Code Online (Sandbox Code Playgroud)
但是有没有更简洁的项目方法可以做到这一点?
ranges::sort(particles, {}, &std::get<0>);
Run Code Online (Sandbox Code Playgroud) C++20 引入了std::common_iterator能够将元素的非公共范围(迭代器和哨兵的类型不同)表示为公共范围(它们相同)的 a ,其概要定义为:
template<input_or_output_iterator I, sentinel_for<I> S>
requires (!same_as<I, S> && copyable<I>)
class common_iterator {
// ...
private:
variant<I, S> v_; // exposition only
};
Run Code Online (Sandbox Code Playgroud)
它对于与期望范围的开始和结束具有相同类型的遗留代码进行交互非常有用。
在[iterators.common#common.iter.types-1.1] 中,其iterator_concept定义为:
iterator_concept表示forward_iterator_tag如果I模型forward_iterator;否则表示input_iterator_tag。
为什么common_iterator最多只能是 a forward_iterator,而不能完全定义其iterator_concept基于I's iterator_category?例如,如果I是random_asscess_iterator,则common_iterator<I, S>是random_asscess_iterator,依此类推。
看来,这是因为技术上是可行的common_iterator只是使用std::variant类型为擦除I和S。
考虑以下(Godbolt): …
考虑以下无用的概念C:
template<class T>
concept C = static_cast<T>(true);
Run Code Online (Sandbox Code Playgroud)
如果我们C在未评估的上下文中传递任意类型,那么所有三个编译器都将成功编译:
struct S {};
decltype(C<S>) x = 0;
Run Code Online (Sandbox Code Playgroud)
但是如果我们在未评估的上下文中传递int给C:
decltype(C<int>) y = 0;
Run Code Online (Sandbox Code Playgroud)
GCC 仍然接受它,而 Clang 和 MSVC 以相同的错误消息拒绝它:
<source>:2:13: error: atomic constraint must be of type 'bool' (found 'int')
Run Code Online (Sandbox Code Playgroud)
上面的代码仍然格式良好吗?我应该信任哪个编译器?
该代码有效吗?
template<bool b>
struct s {
void f() const {
}
static void f() requires b {
}
};
void g() {
s<true>().f();
}
Run Code Online (Sandbox Code Playgroud)
clang 说是,但 gcc 说不
<source>: In function 'void g()':
<source>:10:20: error: call of overloaded 'f()' is ambiguous
10 | s<true>().f();
| ~~~~~~~~~~~^~
<source>:3:14: note: candidate: 'void s<b>::f() const [with bool b = true]'
3 | void f() const {
| ^
<source>:5:21: note: candidate: 'static void s<b>::f() requires b [with bool b = true]'
5 | …Run Code Online (Sandbox Code Playgroud) 考虑以下无用的代码片段,它在不同的编译器中给出不一致的结果(演示)
\n#include <type_traits>\n\nchar* dummy;\nconst char* const& a = dummy;\n char* & b = dummy;\nusing T = decltype(true ? a : b);\nstatic_assert(std::is_same<const char* const&, T>::value); // pass in Clang and MSVC:c++20\nstatic_assert(std::is_same<const char* , T>::value); // pass in GCC and MSVC:c++17\nRun Code Online (Sandbox Code Playgroud)\nGCC认为T存在const char*于C++的所有版本中,而Clang认为存在const char* const&于所有版本中;MSVC 认为T在const char*C++17 和const char* const&C++20 下。
从语言律师\xe2\x80\x99s的角度来看,我应该相信哪个编译器?
\n由于std::variant不允许在标准库中与其替代类型之一进行比较,我正在使用 C++20<=>运算符实现比较函数:
template <typename... Args, typename T>
constexpr auto operator<=>(const std::variant<Args...>& v, const T& t) {
return std::visit([&t](const auto& u) -> std::partial_ordering {
if constexpr (requires { u <=> t; }) return u <=> t;
else return std::partial_ordering::unordered;
}, v);
}
Run Code Online (Sandbox Code Playgroud)
但是当我使用自己定义的测试上述函数时std::variant:
using Variant = std::variant<double, int, std::string_view>;
constexpr Variant v1{1.0};
constexpr Variant v2{1};
constexpr Variant v3{"hello"};
static_assert(v1 < 2);
// compile error
static_assert(v2 < 2);
static_assert(!(v3 > 2) && !(v3 < 2) && …Run Code Online (Sandbox Code Playgroud) 我发现 std::visit 可以按以下方式使用:
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>)
std::cout << "int with value " << arg << '\n';
else if constexpr (std::is_same_v<T, std::string>)
std::cout << "std::string with value " << std::quoted(arg) << '\n';
else
static_assert(always_false_v<T>, "non-exhaustive visitor!");
}, v);
Run Code Online (Sandbox Code Playgroud)
但相反,我想我也可以使用
if(auto x = std::get_if<int>(&v))
std::cout << " is int " << *x << std::endl;
else if(auto x = std::get_if<std::string>(&v))
std::cout << " is String " << *x << std::endl;
else
std::cout << "non-exhaustive visitor!" …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++20 ×8
c++-concepts ×3
std-ranges ×3
c++17 ×2
range-v3 ×2
c++23 ×1
iterator ×1
std-variant ×1
stdvector ×1
templates ×1
variant ×1