Как передать указатель на функцию-член шаблона, не являющуюся типом?

Я хотел бы передать (функции-члену шаблона) указатель на другую функцию-член шаблона в качестве параметра, не являющегося типом шаблона.

Вот что я пробовал:

enum Unit { model_unit, nanometers, meters };

struct Material {
     double rho;
};

struct Point {
    double x, y, z;
};

struct Impl{

    template<Unit unit>
    Material * LookupMat_1(const Point& p) {
        return nullptr; // let's suppose it returns a valid pointer
    }

    template<Unit unit>
    Material * LookupMat_2(const Point& p) {
        return nullptr; // let's suppose it returns a valid pointer
    }

    // compiler error here:
    // expected 'class' or 'typename' before 'Material'
    // template<template<Unit> Material * (Impl::*LookupFunc)(const Point&)
    //                         ^~~~~~~~
    template<template<Unit> Material * (Impl::*LookupFunc)(const Point&) >
    Material * GetMaterial(const Point & p) {

        return (this->*LookupFunc<Unit::model_unit>)(p);
    }

    void DoSomething() {

        Point p = {};

        auto mat_1 = GetMaterial<LookupMat_1>(p);
        auto mat_2 = GetMaterial<LookupMat_2>(p);
    }
};

int main() {

    Impl i;

    i.DoSomething();

}

Мой синтаксис неверен, компилятор говорит:

main.cpp:25:29: error: expected 'class' or 'typename' before 'Material'
template<template<Unit> Material * (Impl::*LookupFunc)(const Point&)
                        ^~~~~~~~

Я не могу понять правильный синтаксис.

LookupFunc - это шаблон типа Material * (Impl::*)(const Point&), который является указателем на функцию-член.

Возможно ли то, что я пытаюсь сделать?

Что мне не хватает?

Параметр шаблона шаблона всегда является шаблоном класса, а не шаблоном функции. Синтаксис всегда template <...> class-or-typename.

n. 'pronouns' m. 11.04.2018 13:55

@ n.m. Могу ли я сделать это, используя шаблонный класс в качестве функтора?

ThreeStarProgrammer57 11.04.2018 14:07

Нет указателей на шаблоны. Однако вы можете использовать указатели на конкретные экземпляры шаблонов.

PaulR 11.04.2018 14:11

Может быть, это продвинет Вас вперед: stackoverflow.com/questions/213761/…

Robert Andrzejuk 11.04.2018 14:12

А также: stackoverflow.com/questions/10115048/…

Robert Andrzejuk 11.04.2018 14:14

@PaulR Да, но я хотел бы, чтобы шаблон был создан с помощью экземпляра GetMaterial, поэтому мне не нужно предоставлять модуль на сайте вызова GetMaterial.

ThreeStarProgrammer57 11.04.2018 14:17
использование класса шаблона в качестве функтора Да, я считаю, что это должно быть возможно.
n. 'pronouns' m. 11.04.2018 16:11
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
264
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Как объясняется в комментариях, нет единого указателя на функцию (или метод) шаблона, потому что это не функция, а набор функций.

Лучшее, что я могу представить, чтобы сделать что-то подобное (я имею в виду ... объяснение типа Unit внутри GetMaterial()), - это добавить пару подструктур в Impl с помощью статических шаблонных методов.

   struct lm1
    {
      template <Unit U>
      static Material * func (Point const & p)
       { return nullptr; }
    };

   struct lm2
    {
      template <Unit U>
      static Material * func (Point const & p)
       { return nullptr; }
    };

затем перепишите GetMaterial() следующим образом

template <typename T>
Material * GetMaterial (Point const & p)
 { return T::template func<Unit::model_unit>(p); }

и используйте это так

void DoSomething()
 {
   Point p = {};

   auto mat_1 = GetMaterial<lm1>(p);
   auto mat_2 = GetMaterial<lm2>(p);
 }

Таким образом, вы передаете GetMaterial() единственный тип (lm1 или lm2), который содержит полный набор функций шаблона; затем внутри GetMaterial() вы выбираете правильную функцию, описывающую Unit::model_unit.

Ниже приведен полный рабочий пример.

enum Unit { model_unit, nanometers, meters };

struct Material
 { double rho; };

struct Point
 { double x, y, z; };

struct Impl
 {
   struct lm1
    {
      template <Unit U>
      static Material * func (Point const & p)
       { return nullptr; }
    };

   struct lm2
    {
      template <Unit U>
      static Material * func (Point const & p)
       { return nullptr; }
    };


   template <typename T>
   Material * GetMaterial (Point const & p)
    { return T::template func<Unit::model_unit>(p); }

   void DoSomething()
    {
      Point p = {};

      auto mat_1 = GetMaterial<lm1>(p);
      auto mat_2 = GetMaterial<lm2>(p);
    }
 };

int main ()
 {
   Impl i;

   i.DoSomething();
 }

Большое спасибо! Почему template требуется в return T::template func<Unit::model_unit>(p);? Я такого никогда не видел.

ThreeStarProgrammer57 11.04.2018 15:12

@ ThreeStarProgrammer57 - иногда требуется, чтобы template сообщил компилятору, что вызываемый метод является методом template; честно говоря, мне очень трудно понять, когда именно требуется, а когда нет. Этот случай кажется обязательным.

max66 11.04.2018 16:59
Ответ принят как подходящий

Вот способ сделать это класс-шаблон-как-функтор.

template<Unit unit>
struct LookupMat_1
{
   Material * operator()(const Point& p) {
       return nullptr;
   }
};

template<Unit unit>
struct LookupMat_2
{
   Material * operator()(const Point& p) {
       return nullptr;
   }
};

template<template<Unit> typename LookupMat>
Material * GetMaterial(const Point & p)
{
    return LookupMat<Unit::model_unit>()(p);
}

Да, именно этим я и закончил после прочтения твоего комментария. Спасибо!

ThreeStarProgrammer57 11.04.2018 17:53

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