假设我有一个使用cmake的C++单元测试项目,如下所示:
$ tree
.
??? C-API-ConditionVariable-unit-test
? ??? C-API-ConditionVariable-compile-link-test.c
? ??? C-API-ConditionVariable-unit-test-0.cpp
? ??? C-API-ConditionVariable-unit-test-1.cpp
??? C-API-Mutex-unit-test
? ??? C-API-Mutex-compile-link-test.c
? ??? C-API-Mutex-unit-test-0.cpp
? ??? C-API-Mutex-unit-test-1.cpp
??? some
? ??? deeply
? ??? nested
? ??? path
? ??? SomeFeature-unit-test
? ??? SomeFeature-compile-link-test.c
? ??? SomeFeature-unit-test-0.cpp
? ??? SomeFeature-unit-test-1.cpp
??? CMakeLists.txt
Run Code Online (Sandbox Code Playgroud)
子文件夹中的每个源文件都会创建一个单独的可执行文件.我希望项目中的每个子文件夹都是非独立模块 - 即每个子文件夹都是(或多或少)自包含的,但不是一个可以单独编译的独立cmake项目.我希望能够只建造一切或什么都不做.例如,我不想让人觉得你只能运行cmake some/deeply/nested/path/SomeFeature-unit-test
来构建它.
我应该选择哪个选项?
CMakeLists.txt
文件在每个子文件夹+ add_subdirectory()
顶级CmakeLists.txt
;some-random-name.cmake
在每个子文件夹+ include()
顶级CmakeLists.txt
;CMakeLists.txt
附加cmake文件中,仅作为帮助程序(宏,函数,...);第一个选项是最方便的,但它表明每个子文件夹实际上是一个可以单独编译的独立项目.
第二种选择似乎清楚地表明这里只有一个cmake项目.但是在每个some-random-name.cmake
子文件夹中,我必须使用源文件的完整路径,这违背了我希望每个文件都是自包含的.如果只有一个级别的嵌套(比如前两个示例子文件夹),那就没关系,但是some/deeply/nested/path/SomeFeature-unit-test
这样做并不是那么好.我还必须在输出文件的名称前加上前缀.
第三种选择似乎是一种快速创建具有CMakeLists.txt …
在Python 3.3中,collections
(如MutableMapping
或MutableSequence
)中的“抽象基类” 被移至了第二级模块collections.abc
。因此,在Python 3.3+中,实际类型为collections.abc.MutableMapping
依此类推。文档指出,旧别名(例如collections.MutableMapping
)将在Python 3.7(当前为最新版本)中可用,但是在3.8中将删除这些别名。
当您使用别名时,当前版本的Python 3.7甚至会产生警告:
./scripts/generateBoard.py:145: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
elif isinstance(value, (collections.MutableMapping, collections.MutableSequence)) == True:
Run Code Online (Sandbox Code Playgroud)
在python 2.7中没有collections.abc
。
当Python脚本打算(几乎)与任何Python版本一起使用时,如何以最便捷的方式处理这种差异?我正在寻找一种解决方案,理想情况下可以在一个中央位置解决此混乱情况,而不必try: ... except: ...
在需要这种类型的所有地方都使用整个脚本?
下面的测试代码与GCC 4.8(和4.7)完全一致:
#include <type_traits>
template<typename T, T &object, typename... Args>
struct Functor
{
template<float (T::*function)(Args...), Args... args>
struct Inner
{
float operator()() const
{
return (object.*function)(args...);
}
};
};
class Object
{
public:
float someFunction()
{
return {};
}
float someFunctionWithArgument(int)
{
return {};
}
};
Object object;
Functor<Object, object>::template Inner<&Object::someFunction> functor1;
Functor<Object, object, int>::template Inner<&Object::someFunctionWithArgument, 1> functor2;
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
然而,对于GCC 4.9,它在实例化时失败了,并且没有任何帮助functor1
:
$ g++ -std=c++11 test.cpp
test.cpp: In instantiation of ‘struct Functor<Object, (* & object)>’:
test.cpp:33:24: …
Run Code Online (Sandbox Code Playgroud) 首先让我说我正在为微控制器创建软件,因此RAM的使用很重要,将大量的const数据块放到非易失性(闪存)内存中是有意义的.
我想要实现的是找到一种在C++中创建"拆分"对象的好方法.举个例子,我们假设有一个字节的数据(读/写)和一个用于访问它的多字节"收据".假设"收据"是一个长字符串,它是一个文件名,并且它指向的媒体很慢,所以在内存中缓冲单个字节是有意义的,而不是在每个请求上实际读取它.
class Data
{
uint8_t byte;
bool valid;
const char filename[128];
uint8_t read()
{
if (!valid)
performReallySlowRead(filename, &byte);
valid = true;
return byte;
};
void write(uint8_t new_value)
{
byte = new_value;
performRealWriteToMedia(filename, byte);
valid = true;
};
}
Run Code Online (Sandbox Code Playgroud)
这种方法的明显问题是整个130字节最终在RAM中,而其中只有两个需要更改.所以我想出了一个分裂对象的想法:
class DataNonConst
{
uint8_t byte;
bool valid;
}
class DataConst
{
const char filename[128];
DataNonConst * const data;
}
static DataNonConst storage;
const DataConst holder("some_long_name_here", &storage);
Run Code Online (Sandbox Code Playgroud)
现在唯一的问题是,如果我想拥有几百个这样的分裂对象,那么创建它们的过程(因此创建两个对象并将第二个链接到第一个)会变得非常无聊和有问题......
所以问题是 - 是否有一些很好的方法可以使它更容易使用,最好是一个聪明的C++技巧或者一些模板魔术?那就是 - 如何使用单个语句创建链接在一起的两个对象,最好隐藏一个对象?我不认为宏解决方案是可行的,因为没有简单的方法来自动创建存储对象的名称...对象需要是相同的类型,因为我需要在其他地方嵌入指向这些对象的指针(一个函数处理写它们,其他只关心阅读)...我想到的所有解决方案要么使用虚拟接口到模板(所以你通过vtable指针使对象更大并且可能得到奖金模板-bloat)或导致巨大的模板膨胀......
编辑:
实际上整个问题的一部分可以简化为一个简单的问题 - 有没有办法将匿名变量"绑定"到C++中的成员字段?就像:
const ConstData holder("...", NonConstData()); …
Run Code Online (Sandbox Code Playgroud) 我写的代码在GCC 4.9,GCC 5和GCC 6中是无警告的.它也是一些较旧的GCC 7实验快照的警告(例如7-20170409).但是在最近的快照(包括第一个RC)中,它开始产生关于别名的警告.代码基本归结为:
#include <type_traits>
std::aligned_storage<sizeof(int), alignof(int)>::type storage;
int main()
{
*reinterpret_cast<int*>(&storage) = 42;
}
Run Code Online (Sandbox Code Playgroud)
使用最新的GCC 7 RC进行编译:
$ g++ -Wall -O2 -c main.cpp
main.cpp: In function 'int main()':
main.cpp:7:34: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
*reinterpret_cast<int*>(&storage) = 42;
Run Code Online (Sandbox Code Playgroud)
(有趣的观察是,禁用优化时不会产生警告)
使用GCC 6进行编译完全没有警告.
现在我想知道,上面的代码肯定有类型 - 惩罚,毫无疑问,但是不是std::aligned_storage
故意用这种方式?
例如,此处给出的示例代码通常不会对GCC 7发出警告,但仅仅是因为:
std::string
不知何故不受影响,std::aligned_storage
使用偏移量访问.通过改变std::string
进int
,消除抵消访问std::aligned_storage
和删除无关的部分,你会得到:
#include <iostream>
#include <type_traits>
#include <string>
template<class T, std::size_t N>
class static_vector
{ …
Run Code Online (Sandbox Code Playgroud) 我想要做的是最好用一个例子来描述:
class A
{
int f1();
int f2();
int f3();
typedef int (A::*ptr)();
constexpr static const ptr array[3] =
{
&A::f1,
&A::f2,
&A::f3,
};
template<ptr a[]>
int sum()
{
int s = 0;
for (int i = 0; i < 3; i++)
s += (this->*a[i])();
};
int f4() { return sum<array>(); };
};
Run Code Online (Sandbox Code Playgroud)
它显然不起作用,在GCC中给出以下输出(在模板实例化的行中,定义似乎很好):
main.cpp: In member function 'int A::sum()':
main.cpp:49:2: warning: no return statement in function returning non-void [-Wreturn-type]
main.cpp: In member function 'int A::f4()':
main.cpp:51:31: error: no matching …
Run Code Online (Sandbox Code Playgroud) 可以在 an 内部使用什么最简单的方法if()
来检测给定的 CMake 变量名称是否是“缓存变量”而不是常规变量?
考虑以下示例:
set(regularVariable "some value")
set(aVariableInCache "some other value" CACHE INTERNAL "")
get_cmake_property(variables VARIABLES)
foreach(variable ${variables})
if(???)
...
endif()
endforeach()
Run Code Online (Sandbox Code Playgroud)
我正在寻找一种简单的方法来区分regularVariable
并且aVariableInCache
仅基于哪个在 CMake 缓存中,哪个只是常规变量。
在处理微控制器时,有一些本质上是全局的 - 我正在考虑外围设备,如串行端口或其他接口.还有外围设备不仅是全局的,而且只有一个(并且永远不会有更多) - 如外围控制核心时钟或中断控制器.这些外设确实具有某种全局状态(例如 - 核心时钟被设置为某种东西)并且反向计算这些值是低效的.
如果我希望我的程序很好地面向对象,我很难决定如何处理这些对象...全局变量并不好,这很明显,但我只是不知道(不够经验)我是否应该试图"隐藏"这些东西是全局的事实......例如"cin"或"stdout"也是全局的(让我们忽略这样一个事实:在多线程应用程序中这些通常是特定于线程的)并且没有人隐藏着......让我们坚持使用时钟发生器外设 - 只有一个,所以我可以使用单例反模式(;或者让类静态或者让单个对象全局化(这就是我通常所做的) ,因为这个对象存储了当前时钟设置,所以很多其他东西都需要这个值 - 需要设置RTOS使用的系统定时器,需要为其他外设设置时钟(UART波特率,SPI比特率......) ,需要为外部存储器设置正确的时钟或配置存储器等待状态.这就是我认为的原因 在main()中创建一个对象并将其传递到任何地方会有点麻烦......
我可以编写方法,以便所有"全局"信息都来自外设寄存器(例如核心频率可以从当前的PLL设置反向计算),但这似乎也是一个错误的想法,更不用说创建对象了对于时钟发生器外围设备到处都会看起
当前的时钟设置可以存储在类的静态成员中,但是从这里开始,只有一小步朝向完全静态的类(因为"this"指针对于没有状态的类来说是无用的)...
通常在非面向对象程序中找到的解决方案最接近完全静态类 - 只有对全局变量进行操作的函数.
任何人都有一个很好的想法如何很好地处理这种情况或这个问题是否值得花时间?也许我应该只使用一个全局对象并完成它?(;
我为我的嵌入式 MCU 项目做了一个非常简单的池分配器。这是一个模板化的类,接口如下(实现部分略过,有兴趣的我也可以贴出来):
template <typename T, size_t size>
class SimplePoolAllocator
{
public:
SimplePoolAllocator();
T * allocate();
void deallocate(T *pointer);
...
}
Run Code Online (Sandbox Code Playgroud)
它非常适用于“简单”的东西,比如类或 POD,例如:
SimplePoolAllocator<double, 10> poolOfDouble; // returns "double *"
SimplePoolAllocator<WeirdClass, 5> poolOfObjects; // returns "WeirdClass *"
Run Code Online (Sandbox Code Playgroud)
如果我想将它用于固定大小的数组,就会出现问题。这种用途当然用于原始数据缓冲区 - 在我的项目中,我有两种“传输”类型,一种有 16 个字节,另一种有 100 个。
所以假设我像这样使用某事:
SimplePoolAllocator<uint8_t[16], 10> pool1;
SimplePoolAllocator<uint8_t[100], 10> pool2;
Run Code Online (Sandbox Code Playgroud)
一切看起来都很好,但问题是现在allocate() 返回这样的东西:“uint8_t(*)[16]”和“uint8_t(*)[100]”。理想情况下,我希望它在这种情况下只返回“uint8_t *”(指向开头的指针)。
我知道我可以这样做:
uint8_t *p = *pool1.allocate(); // additional asterisk to "drop" the array thing from the type
Run Code Online (Sandbox Code Playgroud)
但这看起来……很奇怪……
所以问题是 - 我怎样才能改进我的 SimplePoolAllocator 的接口(或任何东西)来支持“普通”对象(如上所示 - 类和 POD)和固定大小数组的简单分配,但只返回指向第一个元素的指针?可以在不使用 std::array …
让我们从一个代码开始(请注意缩短以仅显示有问题的部分).
#include <type_traits>
#include <utility>
#include <list>
#include <forward_list>
#include <functional>
template<typename Container, typename Compare>
class SortedContainer
{
public:
template<typename... Args>
auto erase(Args&&... args) -> decltype(std::declval<Container>().erase(std::forward<Args>(args)...))
{
return container_.erase(std::forward<Args>(args)...);
}
decltype(std::declval<const Container>().size()) size() const
{
return container_.size();
}
private:
/// container used for keeping elements
Container container_;
};
SortedContainer<std::list<int>, std::less<int>> list;
SortedContainer<std::forward_list<int>, std::less<int>> forward_list;
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
SortedContainer
如果底层Container
没有匹配签名所需的函数,我想有选择地禁用模板中的一些函数.
上面的例子失败了,因为std::forward_list
没有erase()
和size()
函数:
$ g++ -std=c++11 test.cpp
test.cpp: In instantiation of ‘class SortedContainer<std::forward_list<int>, std::less<int> …
Run Code Online (Sandbox Code Playgroud) c++ ×7
templates ×4
c++11 ×3
cmake ×2
embedded ×2
gcc ×2
allocation ×1
arrays ×1
gcc7 ×1
python ×1
python-2.7 ×1
python-3.x ×1