我有一个浮动向量,我将其视为2D数组,声明为
std::vector<float> vec(height*width);
Run Code Online (Sandbox Code Playgroud)
我正在处理的数值问题需要在行和列中处理相同的算法,所以我希望能够通过迭代器编写它们,并且只需输入行迭代器或列迭代器.
为了澄清,这里是访问数组的指针算术版本:
valueatxy = vec[y*width + x];
Run Code Online (Sandbox Code Playgroud)
行迭代器形式当然是微不足道的,比方说我有一个函数template<class iter> void process(iter begin, iter end)
,调用是
process(vec.begin(), vec.end());
Run Code Online (Sandbox Code Playgroud)
现在为了能够使用相同的函数进行列操作,我需要一个列迭代器.这与通常的向量迭代器基本上是相同的迭代器,除了增量运算符和所有其他类似指针算术的运算符,以宽度的倍数递增.电话应该是这样的
process(columnit(vec.begin() + x, width),
columnit(vec.begin() + x + width, width));
Run Code Online (Sandbox Code Playgroud)
columnit
列迭代器类在哪里构造,以按宽度步长递增底层迭代器.
现在,我的问题是,定义这样一个修改过的迭代器的最简单方法是什么?从头开始定义一个新的迭代器涉及很多样板,至少如果我希望它甚至是远程stl兼容的话.Boost迭代器适配器旨在帮助解决这个问题,而且它显然是一个选项,但由于我认为我不需要Boost做其他任何事情,这似乎有点过分.
由于我需要的迭代器的具体修改是如此微不足道,我想可能会有一个更简单的方法,就像有人已经制作了我需要的那种适配器?
我有一个模板类,它有两个静态成员变量,一个int
和另一个std::array<volatile uint_fast32_t, 8>
.当我将具有两个不同类(模板本身)的模板实例化为模板参数时,对于其中一个实例,一切都完美无缺,即两个变量只有一个副本.但是,对于另一个,数组在符号表中显示为重复,实际上我的代码有一个错误,当我在一个编译单元中的数组中设置一个值时,更改不会出现在另一个编译单元中.
这是针对嵌入式系统的,这就是使用静态模板进行编译时多态的这种奇怪习惯的原因.
在代码中:标题声明类本身
//dacmux.h
namespace HAL {
template<typename dac_write_sequence_t,
unsigned int chans,
typename sample_t = uint_fast32_t>
struct dacmux {
private:
typedef std::array<volatile sample_t, chans> chans_t;
static chans_t channels;
static unsigned int nextchan;
...
};
//The static variables defined here,
//count on the compiler/linker to make sure
//there is exactly one definition
template<typename dac_write_sequence_t,
unsigned int chans,
typename sample_t>
typename dacmux<dac_write_sequence_t, chans, sample_t>::chans_t dacmux<dac_write_sequence_t, chans, sample_t>::channels{0};
template<typename dac_write_sequence_t, unsigned int chans, typename sample_t>
unsigned int …
Run Code Online (Sandbox Code Playgroud) 我正在研究嵌入式系统,其中一些校准数据存储在闪存中.校准数据存储在一个结构中,该结构放置在链接器知道放置在闪存中的特殊部分中:
struct data_block {
calibration_data mData;
uint16_t mCheckSum;
};
//Define to compile the fixed flash location for image data
const data_block __attribute__((section (".caldata"))) gCalibrationData{};
Run Code Online (Sandbox Code Playgroud)
哪个calibration_data
是包含实际值的另一个POD结构.
问题是如果我现在简单地写下面的内容:
const data_block data{gCalibrationData};
if (CheckSum(&(data.mData)) == data.mCheckSum) {
//do stuff
} else {
//Error
}
Run Code Online (Sandbox Code Playgroud)
这总是进入错误分支,即使闪存中的实际校验和绝对正确(写一点不同使它工作,见下文).
这当然是可以理解的:编译器看到一个const全局对象,它是默认初始化的,所以它知道所有的值,所以我猜它实际上优化了整个if
(如果我通过a调试printf数据uint16_t *
,我实际上得到了正确的价值观).
我认为正确的方法是定义
const volatile data_block __attribute__((section (".caldata"))) gCalibrationData{};
Run Code Online (Sandbox Code Playgroud)
但是,现在我遇到的问题是我无法将volatile变量分配给非volatile,即const data{gCalibrationData};
不能编译.如果我尝试通过a访问,也会出现同样的问题const volatile data_block *
.
我至少有两三种方法可以完成这项工作,我不喜欢它们中的任何一种:
const
(和volatile
)限定符gCalibrationData
.然而,基于编译器不够聪明以保证gCalibrationData永远不会在我的程序中被触及,这是一个黑客攻击,另一方面,我想保持const限定符,因为尝试写入gCalibrationData通过分配是一个难题.gCalibrationData
通过访问const gCalibrationData * volatile …
很简单,有没有更简单的方法来重复一个块一定次数,其中块里面不需要计数器变量?微不足道的解决方案当然是
for (int i = 0; i < repetitions; ++i) {
//do your thing, i is not used here
}
Run Code Online (Sandbox Code Playgroud)
然而,既然我们已经研究了用于迭代容器的标准算法和其他奇特的构造,相比之下,这实际上开始让人觉得有很多样板和细节,这应该是一个更简单的案例。例如,我们对变量根本不感兴趣i
等等。
最接近具体问题的是:当我遇到像上面这样的 for 循环时,我需要扫描代码块以查看是否i
实际使用,或者它是否只是一个虚拟计数器。实际上想要对整数 0 执行某些操作的 for 循环的声明repetitions - 1
看起来相同。因此,一个repeat (n)
-type 构造将具有额外的语义信息,即所有迭代都将相同,除了潜在的副作用。
一种选择是制作模板
template<class functor>
repeat(functor fun, unsigned n) {
for (unsigned i = 0; i < n; ++i)
fun();
}
Run Code Online (Sandbox Code Playgroud)
并打电话
repeat([&](){
//do your thing
}, repetitions)
Run Code Online (Sandbox Code Playgroud)
但这对于一个简单的问题来说似乎真的是过度设计的矫枉过正。这可以被宏观化以使使用更好一点,但这肯定无助于过度设计的感觉。
所以一个有效的答案是,我在这里大吃一惊,应该只使用带有计数器的旧 for 循环。
任何标准 C++ 都可以,包括即将推出的标准。
相关问题,例如如何在 C++ 中创建循环一定次数的循环? 以及如何在 C++ …
我正在一个内存不足的嵌入式系统上工作,更重要的是,由于存在实时的软约束(即,如果我们没有按时完成但没有人死,那是一个错误),所以我不能使用动态内存分配。
但是,偶尔需要重新初始化子系统,并且存在许多与“并非一切都正确清理或重置”相关的错误。当然,这正是构造函数和析构函数应该解决的问题,但是由于我们不是动态分配的,因此无法在要销毁对象然后从头分配新对象的地方使用惯用语。此处相关的对象是全局变量)。
因此,最后通常是在构造函数中有设置代码,以及一个彼此相似但不完全相同的reinitialize -type函数,因为reinitialize函数还完成了很多析构函数的工作。
我正在考虑的一种解决方法是编写一个“更新” -template(这只是草稿,可能包含错误且可能无法完成):
template<typename T, typename .. Args>
void renew(T & obj, Args&&... args) {
obj.~T();
new(&obj) T(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)
可以用来重新初始化非动态分配的变量。所以举个例子
A a{17};
... //Do something with a
renew(a, 14);
...//work with the new a, no need to reallocate memory
Run Code Online (Sandbox Code Playgroud)
这将允许在没有动态内存分配的情况下获得构造函数和析构函数(主要是初始化和初始化对象的单一方法)的某些优点。请注意,上面的用法已简化,实际上,这将主要用于主循环中非常特定的点以及代表实际物理子系统的全局对象。
问题:这是明智的做法吗?还是有更好的选择?
这里有一个非常相似的问题,调用构造函数重新初始化object。我问的是很多相同的事情,但特别是在嵌入式编程的情况下,在这种情况下,我无法以动态分配的常规方式进行操作。
当索引仅在运行时已知时,从所需类型的索引默认构造 std::variant 的最简单方法是什么?换句话说,我想写:
const auto indx = std::variant<types...>{someobject}.index();
//...somewhere later, indx having been passed around...
std::variant<types...> var = variant_from_index(indx);
///var is now set to contain a default constructed someobject
Run Code Online (Sandbox Code Playgroud)
请注意,indx
不能进行 constexpr,因此std::in_place_index
在此处不起作用。
这里的问题当然是,由于不知道types...
在编译时调用哪个构造函数,所以基本上必须在编译时构建所有可能的构造函数(或者可能是默认构造的变体)的表,然后访问在运行时。一些模板魔术显然在这里就位,但最干净的方法是什么?
我尝试了以下(在 coliru 上),但索引序列似乎出错了(最后的打印给出了2 0 0
),我很困惑为什么:
编辑:它的工作方式如下固定,我的 constexpr 数组初始化错误。所以现在的问题是,有没有更简洁的方法来做到这一点?
#include <variant>
#include <iostream>
using var_t = std::variant<int, float, const char *>;
//For debug
template<class ...types>
struct WhichType;
template<class T, class U>
struct default_variants;
template<class...Params, std::size_t... I>
struct default_variants<std::variant<Params...>, …
Run Code Online (Sandbox Code Playgroud)