Может ли нетипичный параметр шаблона иметь тип "void *"? - PullRequest
11 голосов
/ 06 мая 2019

Якк - Адам Невраумонт сказал :

Нетипичные параметры шаблона типа void* не разрешены в хотя бы некоторые версии стандарта.

Это правда? Если это правда, в каких версиях стандарта нетипичные параметры шаблона типа void* не разрешены?

(Примечание: как отмечено в комментарий отвечать другой комментарий , это около нетипичных параметров шаблона , не аргументы типа шаблона , который может быть любым действительным идентификатором типа за [temp.arg.type] , в том числе void*.

1 Ответ

14 голосов
/ 06 мая 2019

TL; DR

Параметры шаблона типа void* действительны начиная с C ++ 20.Они недействительны до C ++ 20.

C ++ 20

C ++ 20 ослабили ограничения на тип нетипичного параметра шаблона, поэтому давайте сначала исследуем его.

В текущем черновике (по состоянию на UTC 10:00, 6 мая 2019 г.) написано: [temp.param] / 4 :

Нетип шаблон-параметр должен иметь один из следующих (необязательно cv-квалифицированных) типов:

  • литеральный тип, имеющий строгое структурное равенство ([класс.compare.default]),
  • тип ссылки lvalue,
  • тип, который содержит тип заполнителя ([dcl.spec.auto]), или
  • заполнительдля выведенного типа класса ([dcl.type.class.deduct]).

void* - тип указателя.Тип указателя: скалярный тип ( [basic.types] / 9 ). скалярный тип является литеральным типом ( [basic.types] / 10 ).Следовательно, void* является литеральным типом .Первая пуля является соответствующей.

Отслеживая далее, [class.compare.default] / 3 говорит:

Тип C имеет сильное структурное равенство , если при заданном значении x типа const C либо:

  • C является неклассовым типом и x <=> xявляется допустимым выражением типа std::strong_ordering или std::strong_equality, или

  • C - это тип класса с оператором ==, определенным как значение по умолчанию в определении C, x == x правильно формируется при контекстном преобразовании в bool, все подобъекты базового класса C и нестатические члены данных имеют сильное структурное равенство, а C не имеет mutable или volatileподобъекты.

void* относится к неклассному типу, поэтому первый пункт имеет значение.Теперь вопрос сводится к типу x <=> x, где x - это glvalue типа void* const (не const void*).По [expr.spaceship] / 8 :

Если тип составного указателя , тип указателя объекта , p <=> q имеет тип std::strong_­ordering,Если два операнда указателя p и q сравниваются равными ([expr.eq]), p <=> q приводит к std::strong_­ordering::equal;если p и q сравнивать неравно, p <=> q дает std::strong_­ordering::less, если q сравнивает больше p и std::strong_­ordering::greater, если p сравнивает больше q ([expr.rel]).В противном случае результат не указывается.

Обратите внимание, что void* - это тип указателя объекта ( [basic.compound] / 3 ).Следовательно, x <=> x имеет тип std::strong_ordering.Таким образом, тип void* имеет строгое структурное равенство .

Следовательно, в текущем черновике C ++ 20, void* допускается в качестве типа типа параметра шаблона.

C ++ 17

Теперь мы обращаемся к C ++ 17. [temp.param] говорит:

Нетипичный шаблон-параметр должен иметь один из следующих (необязательно квалифицированных cv) типов:

  • целочисленный тип или тип перечисления,
  • указатель на объект или указатель на функцию,
  • lvalue ссылка на объект или lvalue ссылка на функцию,
  • указательчлену,
  • std​::​nullptr_­t или
  • тип, который содержит тип заполнителя.

Обратите внимание, что «указатель на объект» неinclude void* per [basic.compound] / 3 :

[ Примечание: Указатель на void не имеет указателя на-объект типа, однако, потому что void не является типом объекта.- конец примечания ]

Ни одна из шести вышеприведенных позиций не включает void* в качестве возможного типа параметра шаблона.Следовательно, в C ++ 17 параметр шаблона не должен иметь тип void*.

Формулировка одинакова для C ++ 11 и C ++ 14, за исключением того, что отсутствует маркировка о типах заполнителей.,Как правило, до C ++ 20, параметр шаблона не должен иметь тип void*.

Но компиляторы это диагностируют?

TC говорит в комментарии , что никто не диагностирует этот IHRC.Давайте проверим, диагностируют ли это компиляторы в режиме C ++ 17 с минимальным примером, показанным ниже:

template <void*>
class C {};

int main()
{
    C<nullptr> x;
    (void) x;
}

Код компилируется и отлично работает на GCC 9.1.0 , GCC8.3.0 , GCC 7.3.0 , GCC 6.3.0 , GCC 5.5.0 , Clang 8.0.0 Clang 7.0.0 , Clang 6.0.1 и Clang 5.0.0 .

NathanOliver сказал мнев комментарии о том, что кто-то сказал ему, что некоторые компиляторы будут ошибаться, но основные - нет.Поэтому, насколько я могу здесь подтвердить, утверждение ТК верно - никто не ставит диагноз.

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