Я хотел бы передать (функции-члену шаблона) указатель на другую функцию-член шаблона в качестве параметра, не являющегося типом шаблона.
Вот что я пробовал:
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&)
, который является указателем на функцию-член.
Возможно ли то, что я пытаюсь сделать?
Что мне не хватает?
@ n.m. Могу ли я сделать это, используя шаблонный класс в качестве функтора?
Нет указателей на шаблоны. Однако вы можете использовать указатели на конкретные экземпляры шаблонов.
Может быть, это продвинет Вас вперед: stackoverflow.com/questions/213761/…
А также: stackoverflow.com/questions/10115048/…
@PaulR Да, но я хотел бы, чтобы шаблон был создан с помощью экземпляра GetMaterial, поэтому мне не нужно предоставлять модуль на сайте вызова GetMaterial.
Как объясняется в комментариях, нет единого указателя на функцию (или метод) шаблона, потому что это не функция, а набор функций.
Лучшее, что я могу представить, чтобы сделать что-то подобное (я имею в виду ... объяснение типа 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 - иногда требуется, чтобы template
сообщил компилятору, что вызываемый метод является методом template
; честно говоря, мне очень трудно понять, когда именно требуется, а когда нет. Этот случай кажется обязательным.
Вот способ сделать это класс-шаблон-как-функтор.
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);
}
Да, именно этим я и закончил после прочтения твоего комментария. Спасибо!
Параметр шаблона шаблона всегда является шаблоном класса, а не шаблоном функции. Синтаксис всегда
template <...> class-or-typename
.