我有一个编译时有向异步任务的非循环图.DAG显示了任务之间的依赖关系:通过分析它,可以了解哪些任务可以并行运行(在单独的线程中)以及哪些任务需要等待其他任务在它们开始之前完成(依赖关系).
我要生成从DAG回调链,使用boost::future和.then(...),when_all(...)延续辅助功能.这一代的结果将是一个函数,当被调用时,它将启动回调链并执行DAG所描述的任务,并行运行尽可能多的任务.
但是,我遇到了麻烦,找到了适用于所有情况的通用算法.
我做了一些图纸,以使问题更容易理解.这是一个图例,它将向您展示图纸中的符号含义:
让我们从一个简单的线性DAG开始:
这种依赖关系图包括三项任务(A,B,和C).C取决于B.B取决于A.这里没有并行性的可能性 - 生成算法会构建类似于此的东西:
boost::future<void> A, B, C, end;
A.then([]
{
B.then([]
{
C.get();
end.get();
});
});
Run Code Online (Sandbox Code Playgroud)
(请注意,所有代码示例都不是100%有效 - 我忽略了移动语义,转发和lambda捕获.)
有许多方法可以解决这个线性DAG:无论是从结束开始还是从开始开始,构建正确的回调链都是微不足道的.
当引入分支和连接时,事情开始变得更加复杂.
这是一个带有fork/join的DAG:
很难想到与此DAG匹配的回调链.如果我尝试向后工作,从最后开始,我的推理如下:
end取决于B和D.(加入)
D取决于C.B并C依赖A.(叉子)可能的链看起来像这样:
boost::future<void> …Run Code Online (Sandbox Code Playgroud) 我创建了几个目前只有标头的 C++库.我的类的接口和实现都写在同一个.hpp文件中.
我最近开始认为这种设计不是很好:
我真的很喜欢只有头文件库的方面:所有函数都可以内联,并且它们非常容易包含在你的项目中 - 不需要编译/链接任何东西,只需要一个简单的#include指令.
是否有可能充分利用两个世界?我的意思是 - 允许用户选择他/她想要如何使用库.它还可以加快开发速度,因为我以"动态链接模式"处理库以避免荒谬的编译时间,并以"仅标题模式"发布我的成品以最大化性能.
第一个逻辑步骤是将接口和实现划分为.hpp和.inl文件.
不过,我不确定如何前进.我已经看到很多库将LIBRARY_API宏添加到它们的函数/类声明中 - 可能需要类似的东西来允许用户选择?
我的所有库函数都以inline关键字为前缀,以避免"多个定义......"错误.我假设关键字将被文件中的LIBRARY_INLINE宏替换.inl?宏将解析inline为"仅标题模式",而不是"动态链接模式".
从我的个人经验以及从咨询答案到诸如decltype(auto)有什么用途的问题?我可以找到许多有价值的用例decltype(auto)作为函数返回类型占位符。
但是,我在努力思考decltype(auto)变量的任何有效(即有用,现实,有价值)用例时都非常费劲。我想到的唯一可能性是存储函数返回的结果以decltype(auto)供以后传播,但auto&&也可以在此使用,这样会更简单。
我什至搜索了我所有的项目和实验,其中391个出现的decltype(auto)都是返回类型的占位符。
那么,变量是否有实际的用例decltype(auto)?还是仅当用作返回类型占位符时此功能才有用?
您如何定义“现实”?
我正在寻找一个能提供价值的用例(即,不仅仅是显示功能如何工作的示例)decltype(auto),与诸如auto&&或根本不声明变量的替代方案相比,哪里是最佳选择。
问题域无关紧要,它可能是一些晦涩的元编程极端案例或神秘的功能编程构造。但是,该示例需要使我接受“嘿,这很聪明/很漂亮!” 而使用任何其他功能来达到相同的效果将需要更多样板,或者存在某种缺陷。
#include <memory>
struct foo { };
int main() { std::make_shared<foo>(); }
Run Code Online (Sandbox Code Playgroud)
由这两个所产生的asssembly g++7和clang++5与-fno-exceptions -Ofast上面的代码:
包含对单个呼叫operator new,如果-fno-rtti是未通过.
包含两个单独的呼叫到operator new如果-fno-rtti被通过.
这可以在gcc.godbolt.org (clang++5版本)上轻松验证:
为什么会这样?为什么禁用RTTI会阻止make_shared统一对象和控制块分配?
请考虑以下情形:
std::array<int, 8> a;
auto p = reinterpret_cast<int(*)[8]>(a.data());
(*p)[0] = 42;
Run Code Online (Sandbox Code Playgroud)
这是未定义的行为吗?我觉得是这样的.
a.data()返回一个int*,不一样的int(*)[8]
cppreference上的类型别名规则似乎表明它无效reinterpret_cast
作为程序员,我知道指向的内存位置a.data()是一个8 int对象数组
是否有任何我失踪的规则使这个reinterpret_cast有效?
请考虑以下代码段:
template <bool> struct B { };
template <typename T>
constexpr bool pred(T t) { return true; }
template <typename T>
auto f(T t) -> decltype(B<pred(t)>{})
{
}
Run Code Online (Sandbox Code Playgroud)
clang ++ (trunk)编译代码
g ++ (trunk)编译失败,出现以下错误:
src:7:34: error: template argument 1 is invalid
auto f(T t) -> decltype(B<pred(t)>{})
^
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:34: error: template …Run Code Online (Sandbox Code Playgroud)(这是“ “ decltype(auto)变量是否有实际用例? ”的后续文章)
考虑以下情况-我想将一个函数传递f给另一个函数invoke_log_return,该函数将:
调用f;
打印一些东西到stdout ;
返回的结果f,避免不必要的复制/移动并允许复制省略。
请注意,如果f抛出异常,则不应将任何内容打印到stdout。这是我到目前为止的内容:
template <typename F>
decltype(auto) invoke_log_return(F&& f)
{
decltype(auto) result{std::forward<F>(f)()};
std::printf(" ...logging here...\n");
if constexpr(std::is_reference_v<decltype(result)>)
{
return decltype(result)(result);
}
else
{
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
让我们考虑各种可能性:
当f返回prvalue时:
result 将成为一个对象;
invoke_log_return(f)将是一个prvalue(有资格使用复制省略)。
当f返回左值或x值:
result 将作为参考;
invoke_log_return(f)将是一个左值或x 值。
您可以在godbolt.org上看到一个测试应用程序。如您所见, …
我正在研究一个面向数据的实体组件系统,其中组件类型和系统签名在编译时是已知的.
一个实体是一个组件的集合体.可以在运行时从实体添加/删除组件.
甲组件是一个小的逻辑少类.
一个签名是组件类型的编译时间列表.如果实体包含签名所需的所有组件类型,则称该实体与签名匹配.
一个简短的代码示例将向您展示用户语法的外观以及预期用途:
// User-defined component types.
struct Comp0 : ecs::Component { /*...*/ };
struct Comp1 : ecs::Component { /*...*/ };
struct Comp2 : ecs::Component { /*...*/ };
struct Comp3 : ecs::Component { /*...*/ };
// User-defined system signatures.
using Sig0 = ecs::Requires<Comp0>;
using Sig1 = ecs::Requires<Comp1, Comp3>;
using Sig2 = ecs::Requires<Comp1, Comp2, Comp3>;
// Store all components in a compile-time type list.
using MyComps = ecs::ComponentList
<
Comp0, Comp1, …Run Code Online (Sandbox Code Playgroud) 在查看一些C++ 03代码时,我发现了一个让我感到困惑的最令人烦恼的解析实例:
#include <sstream>
#include <string>
int main(int, char** argv)
{
std::stringstream ss(std::string(argv[0]));
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码片段中,ss是一个函数的声明,它接受std::string*并返回std::stringstream.
怎么std::string(argv[0])解析为std::string*?
直觉上,我认为这argv[0]是明确无误的访问argv.
有没有可靠的方法来获取当前输出终端窗口的列数/行数?
我想在C/C++程序中检索这些数字.
我主要是在寻找GNU/Linux解决方案,但也需要Windows解决方案.
c++ ×10
c++11 ×3
auto ×2
c++14 ×2
c++17 ×2
algorithm ×1
asynchronous ×1
c ×1
c++03 ×1
constexpr ×1
copy-elision ×1
future ×1
header-only ×1
libraries ×1
optimization ×1
performance ×1
rtti ×1
shell ×1
terminal ×1