将函数指针分配给 constexpr 结构中的 typedef 函数的正确 C++ 方法是啥?
Posted
技术标签:
【中文标题】将函数指针分配给 constexpr 结构中的 typedef 函数的正确 C++ 方法是啥?【英文标题】:What is the correct C++ way to assign a function pointer to a function of typedef in a constexpr struct?将函数指针分配给 constexpr 结构中的 typedef 函数的正确 C++ 方法是什么? 【发布时间】:2021-07-03 09:36:33 【问题描述】:如果问题措辞不完全准确,请原谅我,但我正在尝试做的(我在使用 MSVC /std:c++latest 编译时所做的)是创建一个配置项的 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_readcfg.read
, m_writecfg.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();
| ^~~~~~~
【问题讨论】:
您显示的错误是您构建时获得的唯一输出吗?如果没有,请将 full 和 complete 构建输出复制粘贴到问题中。请在出现错误的行添加评论。 我不明白。如果要将值复制到Shell
的字段中,为什么需要模板参数?
这是一个gcc bug。
【参考方案1】:
而不是定义这个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_cfgstd::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;
;
【讨论】:
以上是关于将函数指针分配给 constexpr 结构中的 typedef 函数的正确 C++ 方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章