Ma Ming Ma Ming - 8 days ago 7
C++ Question

How to turn a template function in a template class to a function pointer

I am trying to turn a concrete factory into a template factory class. The following is what I wrote; I am working with g++ (GCC) 4.8.5.

The g++ complains that

error: no matches converting function ‘create’ to type ‘using create_t = class Base* (*)() {aka class Base* (*)()}’
. It seams that the sentence
create_t pf = create<S>;
fails, but I have no idea what it is about.

#include<iostream>
#include<type_traits>
class Base {
public:
virtual ~Base() {};
virtual void print() {
std::cout << "In Base." << std::endl;
}
};

class Derived: public Base {
public:
void print() {
std::cout << "In Derived." << std::endl;
}
};


template<typename T>
class Factory {
public:
using create_t = T* (*) ();

template<typename S>
T* create() {
static_assert(std::is_base_of<T, S>::value, "S must be a derived of T.");
return new S();
}

template<typename S>
void test() {
create_t pf = create<S>;
T * pt = pf();
pt->print();
delete pt;
}
};

int main() {
Factory<Base> base_factory;
base_factory.test<Derived>();
return 0;
}

Answer

You miss a static keyword:

template<typename S>
static T* create() {
    static_assert(std::is_base_of<T, S>::value, "S must be a derived of T.");
    return new S();
} 

Demo

Because without static, it's a non-static member function, its type is T* (Factory::*) (); If you really need it as a non-static member function:

using self = Factory;
using create_t = T* (self::*) (); 

template<typename S>
T* create() {
    static_assert(std::is_base_of<T, S>::value, "S must be a derived of T.");
    return new S();
}   

template<typename S>
void test() {
    create_t pf = &self::create<S>;
    T * pt = (this->*pf)();
    pt->print();                                                                                                                                                                                              
    delete pt;
}  

Demo