TL; DR: NULL
является устаревшим C ++. В современном C ++ используйте nullptr
в качестве прямой замены для NULL
, чтобы избежать подобных проблем.
Q: Почему NULL
здесь нельзя передать ? автономный вызов fun с NULL
прекрасно работает
1) В glib c, NULL
в режиме C ++ # определяется как 0L
1
2) Конструктор std::thread
использует std::invoke
to forward его аргументов в вызываемом аргументе. При пересылке значения r * 0L
оно в первую очередь становится переменной (ссылочного типа).
3) Правило неявного преобразования нулевого указателя в C ++ указывается в [conv.ptr] / 1 :
A константа нулевого указателя является целочисленным литералом со значением ноль или значением типа std::nullptr_t
. Константа нулевого указателя может быть преобразована в тип указателя; результат - значение нулевого указателя этого типа и отличается от любого другого значения указателя объекта или типа указателя функции. Такое преобразование называется преобразованием нулевого указателя .
Это означает, что C ++ допускает целочисленных литералов со значением 0 (таким образом, буквально 0
, 0L
, 0u
et c.), Но не другие целые значения , для неявного преобразования в тип указателя:
void fun(void* args) {}
int main() {
fun(0); // OK
int arg = 0;
fun(arg); // error: invalid conversion from 'int' to 'void*'
}
Теперь, поскольку std::invoke
является шаблон, root вызывает ошибку, " недопустимое преобразование из 'long int' в 'void ' *" в вашем случае подпадает под правила SFINAE и молча проглатывается, оставляя вас с неясной ошибкой о проблеме с аргументами std::thread
s.
Обходной путь должен использовать nullptr
вместо NULL
.
1 в режиме C NULL
is (void*)0
, но это запрещено в C ++.