Почему эта функция переводит const char * в void * const, а не const void * - PullRequest
0 голосов
/ 04 ноября 2018

Это очень глупый пример, который я придумал, работая с потоками в Windows, чтобы обернуть const_cast и static_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, поэтому я попробовал gcc и clang на Godbolt , думая, что он наверняка сможет компилироваться, но все равно отказывается с ошибкой сообщение (от gcc 8.2):

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

Почему он пытается привести к void* const вместо const void*, как ожидалось? Есть что-то очевидное, чего мне не хватает?

1 Ответ

0 голосов
/ 04 ноября 2018

Почему эта функция переводит 'const char *' в 'void * const', а не 'const void *'

Поскольку вы использовали void * в качестве аргумента шаблона, и когда вы применяете const к нему, он становится void * const. void * является указателем (на неконстантный объект), а создание указателя 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);

Никаких приведений не требуется (за исключением, очевидно, обратного вызова).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...