为什么此函数将'const char *'强制转换为'void * const'而不是'const void *'

时间:2018-11-03 21:22:43

标签: c++ templates casting

这是一个非常愚蠢的示例,是我在Windows中使用线程将const_caststatic_cast包装到一个线程时出现的

// Somewhere in the OS API
using function_t = void(*)(void *);
void create_thread(function_t function, void *params);

template <typename T, typename U>
T static_const_cast(U ptr) {
  return const_cast<T>(static_cast<const T>(ptr));
}

void thread_proc(const void* name) {
  // ...
}

void test() {
  const char *name = "name";
  void *params = static_const_cast<void *>(name); // Fails
  // void *params = const_cast<void *>(static_cast<const void *>(name));
  // Succeeds (what I want to achieve with static_const_cast)
  create_thread(reinterpret_cast<function_t>(thread_proc), params);
}

但是它无法在Visual Studio 2017上编译,因此我在Godbolt上尝试了gcc和clang,认为它应该可以编译,但仍然拒绝错误消息(来自gcc 8.2):< / p>

error: invalid static_cast from type 'const char*' to type 'void* const'
                                                           ^^^^^^^^^^^^^

为什么它会尝试强制转换为void* const而不是预期的const void*?有什么明显的我想念的吗?

1 个答案:

答案 0 :(得分:3)

  

为什么此函数将'const char *'强制转换为'void * const'而不是'const void *'

因为您使用void *作为模板参数,并且在将const应用于模板参数时,它变为void * constvoid *是一个指针(指向非const对象),将指针设为const会得到const指针,而不是指向const对象的(非const)指针。

您可以执行以下操作来实现所需的目标:

return const_cast<T>(
    static_cast<std::remove_pointer_t<T> const*>(ptr)
);

但是,我建议改用自定义类包装发送到线程的数据。另外,请勿强制转换函数类型。将函数与void*参数一起使用,并将参数转换为函数。

struct params_t {
    const char *name;
};

static params_t params {"name"};

create_thread(thread_proc, &params);

不需要任何强制转换(显然在回调中除外)。