1

I have a strange problem. I want to implement something similar to (https://stackoverflow.com/a/582456/3449968) to retrieve C++ object by name. But my objects use templates. So this is my modification:

template <int dim>
class AspenFunction: public Function <dim>
{
  // define the type of the map to handle all functions
  typedef std::map<std::string, AspenFunction<dim>*(*)()> map_type;

  static AspenFunction * create_aspen_function (const std::string& s)
  {
    typename map_type::iterator it = getMap()->find(s);
    AssertThrow(it == getMap()->end(), ExcMessage("The aspen_function name '" + s + "' is not registered."));
    return it->second();
  }

protected:
  static map_type * getMap()
  {
    if (!_map)
      _map = new map_type;
    return _map;
  }

private:
  static map_type * _map;
};


template <typename T, int dim>
AspenFunction<dim> * createT() { return new T; }

template <typename T, int dim>
class Registrar: AspenFunction <dim>
{
public:
  Registrar(const std::string& s)
  {
    AspenFunction<dim>::getMap()->insert(std::make_pair(s, &createT<T, dim>));
  }
};

template class AspenFunction<2>;

When compiled, I get

Linking CXX executable nssolver
Undefined symbols for architecture x86_64:
   "AspenFunction<2>::_map", referenced from:
      AspenFunction<2>::getMap() in main.cc.o

So, I tried to instantiate _map by adding the following:

template <> AspenFunction<2>::map_type * AspenFunction<2>::_map;

But I get the following error:

/include/equation_handler.h:94:62: error: explicit specialization of '_map' after instantiation
  template <> AspenFunction<2>::map_type * AspenFunction<2>::_map;
                                                             ^
/include/equation_handler.h:69:14: note: implicit instantiation first required here
        if (!_map)
             ^

I don't know what else to do. Am I missing something?

I'm using the following compiler

Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix
Community
  • 1
  • 1
Fahad Alrashed
  • 1,272
  • 2
  • 11
  • 17

1 Answers1

2

You've only declared the static data member _map, it lacks a definition. Add a definition (preferably) immediately after the class definition.

template <int dim>
typename AspenFunction<dim>::map_type *AspenFunction<dim>::_map;

However, I'd do away with the data member completely and change the getMap() function to

static map_type& getMap()
{
  static map_type instance;
  return instance;
}

The instance object will be created the first time getMap() is called, and C++11 guarantees that the instantiation is threadsafe.

Praetorian
  • 106,671
  • 19
  • 240
  • 328