Screndib
Screndib

Reputation: 1014

Is there any way to create a static const variable to a function pointer template parameter (or some equivalent)?

I'm not exactly sure how to word this question so I'll just use an example.

I have a class that takes some template parameters to call a member function of a class:

template<typename T, int V, void (T::*F)(int)>
struct CallFunction
{
    CallFunction()
    {
        T t;
        (t.*F)(V);
    }
};

And I have a class:

struct TestClass
{
    void TestFunc( int x ) { std::cout << "Value is: " << x << std::endl; }
};

I then invoke the CallFunction class:

int main()
{
    CallFunction<TestClass, 5, &TestClass::TestFunc> cf;
}

As expected this is printed:

Value is: 5

Now I decide that I want to add a layer between the template parameters and CallFunction. Rather than provide each template parameter separately to CallFunction I want to create a "Description" class that provides the parameters. So I try something like this:

template<typename D>
struct CallFunctionWithDescription
{
    CallFunctionWithDescription()
    {
        typename D::T t;
        (t.*typename D::F)(typename D::V);
    }
};

template<typename DT, int DV, void (DT::*DF)(int)>
struct Description
{
    typedef DT T;                         // OK
    static const int V = DV;              // OK
    static const void (T::*F)(int) = DF;  // VC++ error C2864!
};

struct TestClass
{
    void TestFunc( int x ) { std::cout << "Value is: " << x << std::endl; }
};

int main()
{
    typedef Description<TestClass, 5, &TestClass::TestFunc> TestClassDescription;
    CallFunctionWithDescription<TestClassDescription> cfd;
}

Not surprisingly this results in: "error C2864: 'Description::F' : only static const integral data members can be initialized within a class".

Is there any mechanism by which I can get a function pointer template parameter into CallFunctionWithDescription via the single type parameter D, or or am I required to pass the function pointer template argument to CallFunctionWithDescription directly?

Upvotes: 2

Views: 802

Answers (1)

Matthieu M.
Matthieu M.

Reputation: 300389

You have two solutions:

  • you may either initialize F out of the class
  • or you may use pattern matching to extract the value

Example of out of class initialization:

template <typename DT, int DV, void (DT::*DF)(int)>
void (DT::* Description<DT, DV, DF>::F)(int) = DF;

Sorry for this reading really bad, function types are never pretty :x

Example of pattern matching:

// Make reading functions a bit easier
template <typename T> struct identity { typedef T type; };

template<typename DT, int DV, void (DT::*DF)(int)>
struct Description
{
    typedef DT T;                         // OK
    static const int V = DV;              // OK
};

template <typename DT, int DV, void (DT::*DF)(int)>
typename identity<void (DT::*)(int)>::type function(Description<DT, DV, DF>) {
  return DF;
}

In essence, you "deconstruct" the type during pattern matching. It requires a bit more writing that the in-class (static) member.

Upvotes: 1

Related Questions