Какова цель третьего параметра шаблона std:: thread constructor?

Вот как объявлен конструктор конструктора std::thread (с использованием Visual Studio 2015):

template<class _Fn,
class... _Args,
class = typename enable_if<
    !is_same<typename decay<_Fn>::type, thread>::value>::type>
explicit thread(_Fn&& _Fx, _Args&&... _Ax)

Нет вопросов относительно _Fn и _Args, однако, что третий class = ... меня полностью смущает. Что он делает, как он работает и для чего он нужен?

Ответы

Ответ 1

Это пример условного включения перегрузки с помощью SFINAE.

Эта перегрузка не должна учитываться при разрешении перегрузки, если первый аргумент имеет тип std::thread.

Обратите внимание, что исходный исходный код стандартных заголовков С++ не предназначен для чтения. Он также не предназначен для мимизации. Разработчики компилятора С++ могут делать много вещей в своих реализациях std-заголовков, которые вы не можете и не должны делать за пределами этих заголовков. Наименьшая из которых запускает переменную с _, за которой следует буква верхнего регистра (которая запрещена в коде пользователя).

Изучите тип аргумента по умолчанию, если _Fn - это std::thread, ссылка на него или ссылка на cv, измененную таким же образом.

typename enable_if<
!is_same<typename decay<_Fn>::type, thread>::value>::type>

decay<_Fn>::type разделяет ссылки и квалификацию cv. Он также преобразует ссылки на функции в указатели на функцию и ссылки на массивы на указатели на первый элемент, но это не важно здесь.

Предположим, что _Fn было thread&. Я буду оценивать:

typename enable_if<
!is_same<typename decay<thread&>::type, thread>::value>::type>
typename enable_if<
!is_same<thread, thread>::value>::type>
typename enable_if<
!true>::type>
typename enable_if<
false>::type>
/* substitution failure occurs */>

enable_if<B>::type существует только в том случае, если B - true; когда _Fn является потоком, он является ложным, поэтому при разрешении перегрузки возникает сбой замены.

SFINAE означает, что сбой замены не является ошибкой, и вместо жалобы компилятора он просто удаляет эту перегрузку с рассмотрения. И thread(thread const&) (который я считаю =delete ed) вместо этого найден конструктор.

Ответ 2

Третий параметр без имени шаблона имеет значение по умолчанию, которое используется для удовлетворения следующего требования конструктора std:: thread через SFINAE, чтобы избежать помех, когда предполагается, что конструктор перемещения вызван.

Этот конструктор не участвует в разрешении перегрузки, если std::decay_t<Function> - это тот же тип, что и std::thread.