C 初始化数组成员,其长度在编译时由构造函数知道
C++ Initializing array member with a length known by constructor at compile time
我正在在显示屏幕的嵌入式设备上编写代码,每个设备都带有一些按钮。屏幕之间的按钮量有所不同,但在编译时已知量。
现在,这是如何设置类的简化版本:
class Button;
class Screen {
private:
Button *buttons;
unsigned int buttonCount;
public:
Screen(Button *_buttons, unsigned int _buttonCount)
: button(_buttons), buttonCount(_buttonCount) {}
};
这是我如何使用它们的想法:
// For this example, Button has a constructor taking a string for
// the button's label
static Button buttonsForMainMenu[] = {
Button("Do this"),
Button("Do that"),
Button("Exit")
};
Screen mainMenu (buttonsForMainMenu, 3);
Screen *currentScreen = &mainMenu;
int main() {
// ...
while (1) {
currentScreen->show();
// handle buttons, etc.
}
}
我想避免使用一个单独的按钮阵列。理想情况下,类似的东西:
Screen mainMenu ({
Button("Do this"),
Button("Do that"),
Button("Exit")
});
此代码适用于不需要动态内存分配的嵌入式系统,因此我想继续避免这种情况。std::array
需要在类声明中声明的数组大小,但是屏幕将具有不同量的按钮。我不相信由于currentScreen
。
是否有一种方法可以让一个数组在其声明/compile-time上找到数组大小?
这可以通过利用C 17的类模板参数扣除来完成。通过将Screen
变成将std::size_t
作为非类型模板参数的模板。然后,通过将参数数传递给构造函数,您可以将其用作模板参数的值。然后,这使您可以在Screen
中制作一个大小的数组。这意味着每个 Screen
hass都有不同数量的按钮是一种不同的类型,但是如果您需要将多个 Screen
s存储在均匀的容器中,则可以从基类继承。
您可以看到使用此最小示例
struct button
{
std::string text;
};
template<std::size_t N>
struct screen
{
button buttons[N];
// constrain Args to only being buttons
template<typename... Args, std::enable_if_t<std::is_same_v<std::common_type_t<Args...>, button>, bool> = true>
screen(Args&&... args) : buttons{std::forward<Args>(args)...} {}
};
// get the number of arguments and use it for the array size
template<typename... Args>
screen(Args... args) -> screen<sizeof...(Args)>;
int main(){
screen a{button{"one"}};
screen b{button{"one"}, button{"two"}};
screen c{button{"one"}, button{"two"}, button{"three"}};
}
以下代码演示了如何使用基类和虚拟函数,因此您可以使用指向基类的指针与不同的screen
s。
struct button
{
std::string text;
};
struct screen_interface
{
void virtual show() = 0;
};
template<std::size_t N>
struct screen : screen_interface
{
button buttons[N];
// contstrain Args to only being buttons
template<typename... Args, std::enable_if_t<std::is_same_v<std::common_type_t<Args...>, button>, bool> = true>
screen(Args&&... args) : buttons{std::forward<Args>(args)...} {}
void show()
{
for (auto const& e : buttons)
std::cout << e.text << "n";
}
};
// get the number of arguments and use it for the array size
template<typename... Args>
screen(Args... args) -> screen<sizeof...(Args)>;
int main(){
screen a{button{"one"}};
screen b{button{"one"}, button{"two"}};
screen c{button{"one"}, button{"two"}, button{"three"}};
screen_interface* si = &b;
si->show();
si = &a;
si->show();
}
做到这一点的一种方法是使用一个模板构造函数通过参考来进行数组:
template<size_t size>
Screen(Button (&_buttons)[size]): buttons(_buttons), buttonCount(size) {}
您会这样使用:
static Button buttonsForMainMenu[] = {
Button("Do this"),
Button("Do that"),
Button("Exit")
};
Screen mainMenu(buttonsForMainMenu);
请注意,由于Screen
只是指向按钮至少与屏幕一样长的按钮。因此,我认为没有一种方法可以在没有动态分配的情况下使用诸如Screen mainMenu({Button("Do this"), ...});
之类的语法,因为在构造函数之后将破坏任何临时数组。
相关文章:
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- 构造函数和 G++ 编译配方的问题
- 编译时生成应在构造函数中创建的非 constexpr 对象数组
- 线程构造函数周围的可变参数模板包装器无法编译
- C++根据调用的构造函数强制编译时错误
- 编译错误:临时对象构造函数中缺少参数
- 为什么删除默认构造函数 A::A() 时会编译"A a{};"?
- c++17在编译时将带有已删除复制构造函数的类添加到std::vector
- std::具有initializer_list和size的unordered_map构造函数在main中编译,但不在类定
- 继承的构造函数,在 clang++3.9 中编译,在 g++ 7 中失败
- 为什么在使用转换构造函数编译代码时需要 const 复制构造函数?
- 将参数传递给 c++ 构造函数时出现 VS 编译错误
- 使用 -pedantic 编译时采用 std::reference_wrapper 的不明确构造函数
- 编译如何选择要拨打的构造函数
- 编译时构造函数选择
- C++编译错误是由于使用 std::move 时运动构造函数与其他非运动构造函数之间的冲突
- 在其他构造函数的调用中调用构造函数时C++编译错误
- 当命名的 lambda 用作模板类参数或构造函数参数时,类模板无法编译
- 无法编译C++构造函数