如何传递模板模板非类型成员函数指针?

时间:2018-04-11 11:43:30

标签: c++ templates template-templates

我想将(指向模板成员函数)指向另一个模板成员函数的指针作为模板模板非类型参数传递。

这是我尝试过的:

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&)
                        ^~~~~~~~

我无法弄清楚正确的语法。

LookupFuncMaterial * (Impl::*)(const Point&)类型的模板,它是指向成员函数的指针。

我正在尝试做什么?

我错过了什么?

2 个答案:

答案 0 :(得分:3)

正如评论中所解释的那样,没有一个指向模板函数(或方法)的指针,因为它不是一个函数,而是一组函数。

我能想象做的最好的事情(我的意思是......在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()传递包含完整模板函数集的单个类型(lm1lm2);然后,在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();
 }

答案 1 :(得分:3)

这里是类模板作为仿函数的方式。

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);
}