Запишите тип указателя на данные члена из других типов шаблонов

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

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, чтобы не нужно было иметь дело с указателями на элементы данных. Как это подходит или упрощает что-то здесь?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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

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

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

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

По стандарту [temp.res]/5:

A qualified name used as the name in a class-or-decltype (Clause 13) or an elaborated-type-specifier is implicitly assumed to name a type, without the use of the typename keyword. In a nested-name-specifier that immediately contains a nested-name-specifier that depends on a template parameter, the identifier or simple-template-id is implicitly assumed to name a type, without the use of the typename keyword. [ Note: The typename keyword is not permitted by the syntax of these constructs. — end note ]

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

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

typenamenested-name-specifieridentifier

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

Уфф, это я пропустил. На самом деле это не удалось в другом контексте, потому что он пытался создать экземпляр указателя на член встроенного типа, что невозможно.

alfC 30.06.2019 03:24

Я обнаружил, что в некоторых случаях мне все равно нужно промежуточное определение, чтобы активировать Sfinae для встроенных типов и не получить серьезную ошибку.

alfC 30.06.2019 08:54

Другие вопросы по теме