Reputation: 3054
I would like to pass (to a template member function) a pointer to a another template member function as a template template non-type parameter.
Here is what I've tried:
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();
}
My syntax is wrong, the compiler says:
main.cpp:25:29: error: expected 'class' or 'typename' before 'Material' template<template<Unit> Material * (Impl::*LookupFunc)(const Point&) ^~~~~~~~
I cannot figure out the right syntax.
LookupFunc
is a template of type Material * (Impl::*)(const Point&)
which is a pointer to a member fonction.
Is what I am trying to do possible?
What am I missing?
Upvotes: 2
Views: 323
Reputation: 120229
Here's the class-template-as-functor way of doing this.
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);
}
Upvotes: 3
Reputation: 66230
As explained in comments, there isn't a single pointer to a template function (or method) because isn't a function but a set of functions.
The best I can imagine to do something similar (I mean... explicating the Unit
type inside GetMaterial()
) is to add a couple of sub-structs in Impl
with static template methods
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; }
};
then rewrite GetMaterial()
as follows
template <typename T>
Material * GetMaterial (Point const & p)
{ return T::template func<Unit::model_unit>(p); }
and use it this way
void DoSomething()
{
Point p = {};
auto mat_1 = GetMaterial<lm1>(p);
auto mat_2 = GetMaterial<lm2>(p);
}
This way you pass to GetMaterial()
a single type (lm1
or lm2
) that contains the full set of template functions; then, inside GetMaterial()
, you select the right function explicating Unit::model_unit
.
The following is a full working example
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();
}
Upvotes: 3