将函数指针分配给 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();
      |      ^~~~~~~

【问题讨论】:

您显示的错误是您构建时获得的唯一输出吗?如果没有,请将 fullcomplete 构建输出复制粘贴到问题中。请在出现错误的行添加评论。 我不明白。如果要将值复制到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++ 方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

将二维指针数组中的字符串分配给一维指针数组

哪些值可以分配给 `constexpr` 引用?

如何将结构中的 void 指针分配给另一个结构?

C中的结构和指针(将字符串分配给结构)

双指针将 char 数组值分配给 char 数组,结构使用 char 指针

将指向结构的指针分配给变量