Template specialization after instantiation?

My complete 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 need to specialize std :: hash for these classes (since the standard definition of std :: hash does not include user-defined types). When I move on to these template specializations before defining the BPCFGParser class, I get a lot of errors for a lot of different things, 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 this class should be complete, and not just declared forward.

So I'm stuck. I cannot specialize templates after defining BPCFGParser , I cannot specify them before defining BPCFGParser , how can I make this work?


You need to move the specialization to the inner class inside BPCFGParser. This meets both requirements.

Thank you very much for your reply:)

hash class is defined in the std . This does not allow me to specialize templates for hash in a domain without a namespace. Even the following:

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

does not work. However, when I conclude the specialization with namespace std {} , this gives a strange error:

 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 the answer given in velocityreviews , someone claims that namespaces cannot be defined inside classes. So I'm still stuck.

+7
c ++ instantiation templates specialization
source share
5 answers

You need to move the specialization to the inner class inside BPCFGParser. This meets both requirements.

  • Specialization after full definition of ActiveEquivClass
  • Before Using 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; }; 
+5
source share

Try moving the hash specialization code <> of the template before declaring the BPCFGParser class. The error means that the hash expands based on std :: hash defined in / usr / include / c ++ / 4.3 / tr1_impl / functional_hash.h; Therefore, your specialization is not used until created. Ideally, your specialization code should be available to the compiler before the template is extended.

+1
source share

Whenever you use a class as a template parameter, the declaration of this class should be complete, and not just declared forward.

This is actually not the case. The limitations of when template parameters must be full types typically depend on the contents of the template; but it is not illegal to create an instance of a template with an incomplete type if the template does not contain code that is illegal with an incomplete type.

The only way to approach your problem is to define specialization in front of the class, but to define the actual member function operator() after the class. I.e

 template <> class std::hash<BPCFGParser::ActiveEquivClass> { public: size_t operator()(const BPCFGParser::ActiveEquivClass & aec) const; }; // definition of BPCFGParser template<> std::size_t std::hash<BPCFGParser::ActiveEquivClass>::operator()(const BPCFGParser::ActiveEquivClass & aec) const { } 

It also means that there are no nested classes, since you cannot redirect the declaration of a nested class.

0
source share

I have exactly the same problem and finally came up with a workaround for hash functions described below:

 class Outer { // TC++PL, 4e, 19.4.1 : A friend must be previously declared in an enclosing scope or // defined in the non-class scope immediately enclosing the class that is declaring it to be a friend. struct Hash_inner; class Inner { int i; friend struct Hash_inner; }; struct Hash_inner { size_t operator()(const Inner& in) const { return std::hash<int>()(in.i); } }; std::unordered_map<Inner, int, Hash_inner> um; }; 

And I wonder if there is a std :: hash specialization approach. Can anyone figure this out?

0
source share

I know this question is pretty old, but I ran into the same problem and I thought I was reporting my findings.

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>' 

doesn’t complain about your classes at all, he says that you cannot specialize std :: hash because either the general template for std :: hash or one of the existing specializations is already used - that is, someone used this between the point, in by which it was defined, and by the point at which you are trying to specialize it.

There are several texts that describe this in the "detail" section of this document :

Specialization must be declared before the first use, which could cause an implicit instance

In my case, the problem was not in my specialization code, the problem was in its position. When std :: hash is used at all, you cannot specialize it.

I found that if I moved my specialization code right after turning on <unordered_map>, it worked fine.

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

0
source share

All Articles