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.
You need to move the specialization into an inner class inside of BPCFGParser. Doing so meets both requirements
ActiveEquivClass
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;
};
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With