C++23 引入了std::function的表兄弟std::move_only_function,就像它的名字一样,它是仅移动可调用对象的仅移动包装器(演示):
#include <functional>
#include <memory>
int main() {
auto l = [p = std::make_unique<int>(0)] { };
std::function<void(void)> f1{std::move(l)}; // ill-formed
std::move_only_function<void(void)> f2{std::move(l)}; // well-formed
}
Run Code Online (Sandbox Code Playgroud)
但与 不同的是std::function,该标准没有为其定义推导指南(演示):
#include <functional>
int func(double) { return 0; }
int main() {
std::function f1{func}; // guide deduces function<int(double)>
std::move_only_function f2{func}; // deduction failed
}
Run Code Online (Sandbox Code Playgroud)
禁止 CTAD 有理由吗?
如果类头名称包含嵌套名称说明符,则该类说明符不应位于类范围内。 如果其类名是标识符,则类说明符应对应于嵌套名称说明符所引用的类、类模板或命名空间中可命名的一个或多个声明;它们都应具有相同的目标范围,并且类说明符的目标范围的目标范围就是该范围。
[例子:
Run Code Online (Sandbox Code Playgroud)namespace N { template<class> struct A { struct B; }; } using N::A; template<class T> struct A<T>::B {}; // OK template<> struct A<void> {}; // OK--结束示例]
第一句话和例子似乎有所不同。
不包含嵌套名称说明符(但仅“依赖”使用A<void>)的模板的专业化是否仍然符合?
clang 和 msvc 接受它,gcc 显示错误
错误:在其命名空间之外显式特化“模板结构 N::A”必须使用嵌套名称说明符 [-fpermissive]
介绍原始措辞和示例注释的论文是P1787R6:声明以及在哪里找到它们,包含以下行:
Run Code Online (Sandbox Code Playgroud)template<> struct A<void> {}; // error: A not nominable in …
我注意到 C++23zip_view有以下限制:
template<input_range... Views>
requires (view<Views> && ...) && (sizeof...(Views) > 0)
class zip_view;
Run Code Online (Sandbox Code Playgroud)
这意味着只能zip_view压缩输入范围。
我想知道为什么它排除output_range,因为output_range在我看来支持可能很有用。例如,我可以压缩一堆output_ranges 来同时写入,如下场景:
/* zipped input_range */
auto zip_in = views::zip(views::iota(0, 3),
views::iota(3, 6),
views::iota(6, 9));
std::vector<int> v1, v2, v3;
auto make_insert_range = [](auto inserter) {
return ranges::subrange(inserter, std::unreachable_sentinel);
};
/* zipped output_range */
auto zip_out = views::zip(make_insert_range(std::back_inserter(v1)),
make_insert_range(std::back_inserter(v2)),
make_insert_range(std::back_inserter(v3)));
/* copy */
ranges::copy(zip_in, zip_out.begin());
std::println("v1: {}", v1); // v1: [0, 1, 2]
std::println("v2: {}", …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,为什么我们要求可调用的呢 …
Cppreference文档包含 5个stdfloat新类型:float16_t、float32_t、float64_t和float128_t。bfloat16_t虽然前 4 种类型是不言自明的(分别是 16、32、64 和 128 位的浮点数),但最后一种类型bfloat16_t对我来说根本不清楚。这个类型代表什么?它的名字中的是什么b意思?
方便的initializer_list语法似乎是以无法移动列表成员、创建不必要的副本为代价的。
struct A
{
// some members which are dynamic resources...
A() { cout << "Default Constructor\n"; }
A(const A& original) { cout << "Copy constructor\n"; }
A(A&& original) { cout << "Move constructor\n"; }
};
int main() {
vector<A> v1{ A() , A() }; // calls copy
vector<A> v2;
v2.push_back(A()); v2.push_back(A()); // calls move
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,这是因为取消引用初始化器迭代器会给出const T,即使尝试移动时也会复制它。
有解决方法吗?
阅读/sf/answers/3101541901/,提出了一种使用可变参数模板的解决方案,如下所示:
template<class Array> struct maker;
// a maker which makes a std::vector
template<class …Run Code Online (Sandbox Code Playgroud) 我知道 iota 可能很复杂(例如无限),因此在一般情况下这不容易完成,但在某些情况下应该可以在 O(1) 中进行查找/包含操作。
例如
int main() {
auto vals = views::iota(10'000'000'000, 100'000'000'000);
return ranges::find(vals, 74'656'000'000) != vals.end();
}
Run Code Online (Sandbox Code Playgroud)
“无限”运行(进行线性搜索)
显然检查可以在 O(1) 内完成。
有没有办法用 C++ 来实现这种通用方式(即在其他视图上查找/包含需要线性时间,并且当它检测到 iota 时需要 O(1)),或者我需要手动检测传递给我的函数的视图是什么时候有限iota视图并进行>=front <=back检查?
class stacktrace_entry {
public:
string description() const;
string source_file() const;
uint_least32_t source_line() const;
/* ... */
};
Run Code Online (Sandbox Code Playgroud)
struct source_location {
// source location field access
constexpr uint_least32_t line() const noexcept;
constexpr uint_least32_t column() const noexcept;
constexpr const char* file_name() const noexcept;
constexpr const char* function_name() const noexcept;
/* ... */
};
Run Code Online (Sandbox Code Playgroud)
它们的目的基本相同,为什么它们有差异,特别是 中没有列stacktrace_entry,或者甚至不共享同一类?
我正在使用 C++23std::optional添加,但我不知道如何优雅地访问对象的值(如果optional处于活动状态)。
我知道我可以使用if,但这就是C ++20 。
我真的很喜欢 C++23 API 的变化,但我不知道如何跳过实现身份的样板。例如:
#include <functional>
#include <iostream>
#include <optional>
void print(std::optional<std::string>& name) {
name.transform([](std::string& x) {
std::cout << x << std::endl;
// I just want to print, without modifying optional, but next line is required
return x;
});
}
int main() {
std::optional<std::string> name{{"Bjarne"}};
print(name);
}
Run Code Online (Sandbox Code Playgroud)
感觉就像std::optional缺少invoke会员功能一样。
注意:在我的示例中,我在转换后不会链接任何其他内容,但为了简洁起见,我关心可选内容是否被修改。
关键字constexpr在引入 C++11 标准时对其函数实施了相当严格的限制。C++14 和 C++20 放宽了这些限制(最值得注意):
return语句static_assert等。try并且asmC++23 进一步软化了这些限制。从我在cppreference中看到的,constexprfor函数似乎只剩下以下含义:
C++23 甚至删除了 constexpr 函数必须在编译时对于p2448r2中的任何类型“可计算”的限制。根据我的理解,这完全消除了constexpr在编译时评估函数的想法。
是这样吗?如果是这样,constexpr函数还有什么用处呢?
c++ ×10
c++23 ×10
c++20 ×3
std-ranges ×3
c++17 ×1
constexpr ×1
stack-trace ×1
std-function ×1
stdoptional ×1