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

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

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

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

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

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

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