c++ - 将函数指针分配给 constexpr 结构中的 typedef 函数的正确 C++ 方法是什么?
问题描述
如果问题措辞不完全准确,请原谅我,但我正在尝试做的(我在使用 MSVC /std:c++latest 编译时所做的)是为一个非常基本的 shell 类创建一个配置项的 constexpr 结构. 其中一些项目是依赖于应用程序/平台的 io 函数,可读写。以下代码适用于我在添加到现有项目之前修改的 VS 解决方案。
...来自仅标题类
typedef size_t (*read_func_t)(void* const buf, size_t nbytes);
typedef size_t (*write_func_t)(const void* buf, size_t nbytes);
typedef struct shell_cfg_t {
size_t buffer_size;
read_func_t read;
write_func_t write;
size_t max_args;
} shell_cfg_t;
template<shell_cfg_t cfg>
class Shell
{
public:
Shell(const cmd_t * const cmd_table)
: m_buf{}
, m_args{}
, m_read{cfg.read}
, m_write{cfg.write}
{
ms_cmd_table = cmd_table;
}
};
...来自 main.cpp
static size_t read_impl(void* const buf, size_t nbytes)
{
// some code
return bytes_read;
}
static size_t write_impl(const void* buf, size_t nbytes)
{
// some code
return bytes_written;
}
constexpr shell_cfg_t cfg =
{
.buffer_size = 64,
.read = read_impl,
.write = write_impl,
.max_args = 8
};
int main()
{
Shell<cfg> sh(shell_cmd_table);
std::string user_input_str;
std::getline(std::cin, user_input_str);
user_input_str += sh.kEoL;
byte_recvd_handler((uint8_t*)(user_input_str.data()), user_input_str.length());
sh.process();
return 0;
}
这里的问题代码似乎是将 read_impl 和 write_impl 分配给结构的 .read 和 .write 。来自 GNU 10.2.0 的错误如下(底部的完整错误):
"error: 'read_impl' is not a valid template argument of type 'size_t (*)(void*, size_t)' {aka 'long long unsigned int (*)(void*, long long unsigned int)'} because 'read_impl' is not a variable, .read = read_impl,"
我正在处理的 GCC 和 MSVC 之间的 C++20 实现是否存在差异,或者此代码是否符合标准?constexpr 结构和命名初始化列表是我认为的新事物,但我认为以这种方式分配函数指针与新的 std 标准没有任何关系。另一种方法是对不是 nullptr 的读/写函数进行运行时检查,这是将配置结构与模板一起使用的重点。有没有更好的方法可以与 C++17 兼容?
编辑:...与此文件相关的完整错误。整个项目输出将是 1000+ 行
../Examples/Example_Shell.cpp: In function 'int main()':
../Examples/Example_Shell.cpp:47:11: error: 'read_impl' is not a valid template argument of type 'size_t (*)(void*, size_t)' {aka 'long long unsigned int (*)(void*, long long unsigned int)'} because 'read_impl' is not a variable
47 | .read = read_impl,
| ^~~~~~~~~
../Examples/Example_Shell.cpp:71:28: error: invalid conversion from 'const cmd_t*' {aka 'const Kernel::Shell::cmd_t*'} to 'int' [-fpermissive]
71 | Kernel::Shell::Term<cfg> sh(shell_cmd_table);
| ^~~~~~~~~~~~~~~
| |
| const cmd_t* {aka const Kernel::Shell::cmd_t*}
../Examples/Example_Shell.cpp:75:24: error: request for member 'kEoL' in 'sh', which is of non-class type 'int'
75 | user_input_str += sh.kEoL; // for example only. getline does not capture end line
| ^~~~
../Examples/Example_Shell.cpp:79:6: error: request for member 'process' in 'sh', which is of non-class type 'int'
79 | sh.process();
| ^~~~~~~
解决方案
而是定义这个constexpr
定义一个类,然后模板将其用作类型参数:
struct shell_default_cfg_t
{
size_t buffer_size;
read_func_t read;
/* static */ size_t read(void* const buf, size_t nbytes) const {
return read_impl(buf, nbytes);
}
/* static */ size_t write_impl(const void* buf, size_t nbytes) {
return write_impl(buf, nbytes);
}
};
template<typename Cfg>
class Shell
{
public:
Shell(const cmd_t * const cmd_table, Cfg cfg)
: m_buf{}
, m_args{}
, m_cfg{std::move(cfg)}
{
ms_cmd_table = cmd_table;
}
size_t read(void* const buf, size_t nbytes) const {
return cfg.read(buf, nbytes);
}
Cfg m_cfg;
};
推荐阅读
- r - 当tabpanel干净时在闪亮的应用程序中显示文本并在显示输出时隐藏它
- r - R 中的 RNA Seq - 如何匹配 CSV 表和元数据之间的 ncol 和 nrow 数字?
- azure-devops - 从 DevOps 任务板中删除工作项类型
- spring-boot - Thymeleaf 模板未在条件内呈现参数值
- javascript - Sequelize include 在另一个 include 中
- php - 按日月年在laravel中制作报告
- java - 如何使用方法引用表示法(Class::method)在 Java 中将方法作为参数传递?
- bash - 使用 bash 在字符串之间查找文本并替换找到的字符串中的文本
- java - 对 java 的 Visual Studio Code 语言支持崩溃了 5 次
- ssas - DAX 计算行中的重复组