1

Here we have two template classes.

The first one named "Factory", it't a singleton-Factory-Model class and have a template-member-function that is responsible for registering class-producer in this factory.

The second named "FactoryRegister", it's only duty is to register T2 in Factory T1.

In the end, we have a macro that declare a FactoryRegister variable, by using this macro in global scope, we realise that register all classes in factories before our program is running.

#include <memory>
#include <mutex>
#include <map>
#include <string>

template <typename Base>
class Factory {
public:

    static std::shared_ptr<Factory<Base> > get_instance() {
        static std::shared_ptr<Factory> factory;
        if (!factory) {
            static std::mutex _new_mutex;
            std::lock_guard<std::mutex> guard(_new_mutex);
            if (!factory) {
                factory.reset(new Factory);
            }
        }

        return factory;
    }

    template <typename Derived,
              typename = typename std::enable_if<std::is_base_of<Base, Derived>::value>::type>
    void add(std::string pname) {
        std::lock_guard<std::mutex> guard(_mutex);
        _producers.emplace(pname, [](std::string name) {return new Derived(name);});
    }

    void del(std::string pname) {
        std::lock_guard<std::mutex> guard(_mutex);
        _producers.erase(pname);
    }

    bool is_exist(std::string pname) {
        return _producers.find(pname) != _producers.end();
    }

    std::shared_ptr<Base> create(std::string pname, std::string name) {
        std::shared_ptr<Base> ret;
        if (is_exist(pname)) {
            ret.reset(_producers[pname](name));
        }
        return ret;
    }

private:
    Factory() = default;

    Factory(const Factory&) = delete;

    Factory& operator=(Factory&) = delete;

private:
    std::mutex _mutex;
    std::map<std::string, std::function<Base*(std::string)> > _producers;
};

template<typename T1, typename T2>
struct FactoryRegister {
    FactoryRegister(std::string name) {
        Factory<T1>::get_instance()->add<T2>(name);
    }
};

#define REGISTER_TO_FACTORY(BaseClass, DerivedClass) \
    const FactoryRegister<BaseClass, DerivedClass> \
    REGISTER_WITH_##BaseClass_##DerivedClass(#DerivedClass)

with codes, the compiler(gcc4.8.2) show below:

factory.h: In constructor 'FactoryRegister<T1, T2>::FactoryRegister(std::string)':
factory.h:62:44: error: expected primary-expression before '>' token
         Factory<T1>::get_instance()->add<T2>(name);

Could any body tell the reason ?

mch
  • 9,424
  • 2
  • 28
  • 42
ciding
  • 11
  • 2
  • 3
    Try `Factory::get_instance()-> template add(name);`. – songyuanyao May 12 '17 at 07:25
  • It works, thx so much Why the 'template' keywords is indeed here? – ciding May 12 '17 at 07:31
  • It's used to tell the compiler that `add` (which is a dependent name) is a template. See [Where and why do I have to put the “template” and “typename” keywords?](http://stackoverflow.com/q/610245/3309790). – songyuanyao May 12 '17 at 07:35

1 Answers1

0

Quote from C++'03 Standard 14.2/4:

When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

Factory<T1>::get_instance()-> template add<T2>(name);

Btw, some compilers has special mode that allows to compile original code without errors

Narek Atayan
  • 1,479
  • 13
  • 27
  • When The Factory is not a template class but a instantiation, The compiler could work successfully without 'template' . for example: struct A { public: A(std::string name) : _name(name) {} std::string _name; }; template struct FactoryRegister { FactoryRegister(std::string name) { Factory::get_instance()->add(name); } }; – ciding May 12 '17 at 07:44