Напишите тип указателя на данные элемента из других типов шаблонов - PullRequest
3 голосов
/ 30 июня 2019

У меня есть функция, которая извлекает указатель на тип члена из других типов, и это работает:

template<class T2, class Array,
    class Element = typename std::decay_t<Array>::element,
    class PointerToMemberType = T2 Element::*
>
v f(Array&& a, PointerToMemberType pm);

Однако я не могу найти способ написать PointerToMemberType = ??? без предварительного определения Element, котороедолжен быть в состоянии быть опущенным.

Как мне написать PointerToMemberType напрямую, без использования вспомогательного Element?

Я пробовал простое замещение, но оно не работает:

template<
    class T2, class Array, 
    class PointerToMemberType = T2 typename std::decay_t<Array>::element::*
>
void f(Array&&, PointerToMemberType pm);
// error: expected identifier before ‘*’ token
  677 |  class PointerToMemberType = T2 typename std::decay_t<Array>::element::* 
                                                                               ^

Я также попытался добавить typename и круглые скобки в нескольких местах.

Обратите внимание, что PointerToMemberType в настоящее время не используется для вычета, хотя я постараюсь использовать его в будущем.

В некоторых местах рекомендуется использовать std::invoke, чтобы не нужно было иметь дело с указателями на члены-данные. Как это могло бы соответствовать или упростить что-то здесь?

1 Ответ

4 голосов
/ 30 июня 2019

Вспомогательная мета-функция вполне бы справилась:

template <typename C, typename M>
using PM = M C::*;

template<
    class T2, class Array, 
    class PointerToMemberType = PM<typename std::decay_t<Array>::element, T2>
>
...

Что касается того, можно ли это сделать "напрямую", ответ - да, но вы должны опустить the typename ключевое слово.Ваш компилятор должен принять это:

template<
    class T2, class Array, 
    class PointerToMemberType = T2 std::decay_t<Array>::element::*
>
...

В соответствии со стандартом, [temp.res] / 5:

Полное имя, используемое в качестве имени в классе.-или-decltype (раздел 13) или уточненный спецификатор типа неявно предполагается для имени типа, без использования ключевого слова typenameспецификаторе вложенного имени , который непосредственно содержит спецификатор вложенного имени , который зависит от параметра шаблона, идентификатор или простой-шаблон-id подразумевается как имя типа без использования ключевого слова typename.[ Примечание: Ключевое слово typename не допускается синтаксисом этих конструкций.- конечная заметка ]

В нашей ситуации у нас есть спецификатор вложенного имени std::decay_t<Array>::element::, который сразу же содержит вложенное имя-specifier std::decay_t<Array>::, который зависит от параметра шаблона, поэтому этот абзац говорит нам, что typename не требуется.Ясно, что когда за std::decay_t<Array>::element следует ::, компилятор знает, что std::decay_t<Array>::element является типом, а не элементом данных или функцией-членом.

Согласно примечанию, грамматика запрещает ненужное использованиеtypename в этой ситуации.Правильное использование спецификатора typename в соответствии с [temp.res] / 3:

typename Спецификатор вложенного имени идентификатор

Здесь typename применяется к идентификатору после применения всего спецификатора вложенного имени , например,в typename A::B::C::D оператор :: связывается более тесно, чем typename, поэтому вы говорите, что typename A::B::C::D является типом. спецификатор вложенного имени не может содержать typename на верхнем уровне одного из его компонентов, поскольку из [expr.prim.id.qual] самый левый компонент может иметь тип -name , namespace-name или decltype-спецификатор и type-name (в отличие от type-id ) может быть только неквалифицированным именем или simple-template-id .Нелевые компоненты могут быть только неквалифицированными именами или simple-template-id s (иногда требуется префикс template).

...