Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specialization of template after instantiation?

My full code is too long, but here is a snippet that will reflect the essence of my problem:

class BPCFGParser {
  public:

  ...
  ...

  class Edge {
    ...
    ...
  };


  class ActiveEquivClass {
    ...
    ...
  };

  class PassiveEquivClass {
    ...
    ...
  };

  struct EqActiveEquivClass {
    ...
    ...
  };

  struct EqPassiveEquivClass {
    ...
    ...
  };



  unordered_map<ActiveEquivClass, Edge *, hash<ActiveEquivClass>, EqActiveEquivClass> discovered_active_edges;
  unordered_map<PassiveEquivClass, Edge *, hash<PassiveEquivClass>, EqPassiveEquivClass> discovered_passive_edges;

};

namespace std {


template <>
class hash<BPCFGParser::ActiveEquivClass>
{

    public:
        size_t operator()(const BPCFGParser::ActiveEquivClass & aec) const {

        }
};

template <>
class hash<BPCFGParser::PassiveEquivClass>
{

    public:
        size_t operator()(const BPCFGParser::PassiveEquivClass & pec) const {

        }
};

}

When I compile this code, I get the following errors:

In file included from BPCFGParser.cpp:3,
                 from experiments.cpp:2:
BPCFGParser.h:408: error: specialization of ‘std::hash<BPCFGParser::ActiveEquivClass>’     after instantiation
BPCFGParser.h:408: error: redefinition of ‘class                 std::hash<BPCFGParser::ActiveEquivClass>’
/usr/include/c++/4.3/tr1_impl/functional_hash.h:44: error: previous definition of     ‘class std::hash<BPCFGParser::ActiveEquivClass>’
BPCFGParser.h:445: error: specialization of     ‘std::hash<BPCFGParser::PassiveEquivClass>’ after instantiation
BPCFGParser.h:445: error: redefinition of ‘class std::hash<BPCFGParser::PassiveEquivClass>’
/usr/include/c++/4.3/tr1_impl/functional_hash.h:44: error: previous definition of     ‘class std::hash<BPCFGParser::PassiveEquivClass>’

Now I have to specialize std::hash for these classes (because standard std::hash definition does not include user defined types). When I move these template specializations before the definition of class BPCFGParser, I get a variety of errors for a variety of different things tried, and somewhere (http://www.parashift.com/c++-faq-lite/misc-technical-issues.html) I read that:

Whenever you use a class as a template parameter, the declaration of that class must be complete and not simply forward declared.

So I'm stuck. I cannot specialize the templates after BPCFGParser definition, I cannot specialize them before BPCFGParser definition, how may I get this working?


You need to move the specialization into an inner class inside of BPCFGParser. Doing so meets both requirements.

Thank you very much for the answer :)

hash class is defined within the namespace std. It does not allow me to specialize the templates for hash in a non-namespace scope. Even the following:

template <>
  class std::hash<ActiveEquivClass> {
...

did not work. When I enclose the specializations with namespace std {}, however, it gives the weird error of:

In file included from BPCFGParser.cpp:3,
                 from experiments.cpp:2:
BPCFGParser.h:225: error: expected unqualified-id before ‘namespace’
experiments.cpp:7: error: expected `}' at end of input
BPCFGParser.h:222: error: expected unqualified-id at end of input

In an answer given in velocityreviews, someone claims that namespaces cannot be defined within classes. So I'm still stuck.

like image 342
Onur Cobanoglu Avatar asked Dec 12 '09 19:12

Onur Cobanoglu


2 Answers

You need to move the specialization into an inner class inside of BPCFGParser. Doing so meets both requirements

  1. Specialization is after the complete definition of ActiveEquivClass
  2. Before the use of the specialization

Example:

class BPCFGParser {

  class ActiveEquivClass {
    ...
  };

  template <>
  class hash<ActiveEquivClass> {
     public:
        size_t operator()(const BPCFGParser::ActiveEquivClass & aec) const {
        }
  };
  ...
  unordered_map<ActiveEquivClass, Edge *, hash<ActiveEquivClass>, EqActiveEquivClass> discovered_active_edges;

};
like image 161
JaredPar Avatar answered Oct 21 '22 23:10

JaredPar


I know this question is quite old, but I've just come across the same problem and I thought I'd report my findings.

The error message:

In file included from BPCFGParser.cpp:3,
             from experiments.cpp:2:
BPCFGParser.h:408: error: specialization of ‘std::hash<BPCFGParser::ActiveEquivClass>’     after instantiation
BPCFGParser.h:408: error: redefinition of ‘class                 std::hash<BPCFGParser::ActiveEquivClass>’
/usr/include/c++/4.3/tr1_impl/functional_hash.h:44: error: previous definition of     ‘class std::hash<BPCFGParser::ActiveEquivClass>’
BPCFGParser.h:445: error: specialization of     ‘std::hash<BPCFGParser::PassiveEquivClass>’ after instantiation
BPCFGParser.h:445: error: redefinition of ‘class std::hash<BPCFGParser::PassiveEquivClass>’
/usr/include/c++/4.3/tr1_impl/functional_hash.h:44: error: previous definition of     ‘class std::hash<BPCFGParser::PassiveEquivClass>’

isn't complaining about your classes at all, it's saying that you can't specialize std::hash because either the generic template for std::hash or one of the existing specializations has already been used - i.e. someone has used it between the point that it was defined and the point where you're attempting to specialize it.

There is some text describing this in the "in detail" section of this document:

Specialization must be declared before the first use that would cause implicit instantiation

In my case, the problem wasn't with my specialization code, the problem was with its position. Once std::hash has been used at all, you can't specialize it any further.

I found that if I moved my specialization code to immediately after including <unordered_map>, it worked fine.

The suggestion by Puppy to separate the declaration of the specialization from the implementation allows you to move the declarations very close to the inclusion of <unordered_map>, the implementation can come later wherever it's convenient (after BPCFGParser is fully defined in your case).

like image 2
sheltond Avatar answered Oct 21 '22 23:10

sheltond