我的完整代码太长了,但这里有一段代码可以反映我问题的实质:
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 {
}
};
}
编译此代码时,出现以下错误:
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>’
现在我必须为这些类专门化std :: hash(因为标准的std :: hash定义不包括用户定义的类型)。当我在类BPCFGParser
的定义之前移动这些模板特化时,我会尝试各种不同的错误,并在某处(http://www.parashift.com/c++-faq-lite/misc-technical-issues.html)我读到:
每当您使用类作为模板参数时,该类的声明必须完整,而不是简单地向前声明。
所以我被困住了。在BPCFGParser
定义之后我无法专门化模板,我无法在BPCFGParser
定义之前对它们进行专门化,我怎么能让它工作?
您需要将专门化移动到BPCFGParser内部的内部类中。这样做符合这两个要求。
非常感谢您的回答:)
hash
类在命名空间std
中定义。它不允许我在非命名空间范围内专门化hash
的模板。甚至如下:
template <>
class std::hash<ActiveEquivClass> {
...
没用。但是,当我用namespace std {}
括起特化时,它会产生奇怪的错误:
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
在velocityreviews中给出的答案中,有人声称无法在类中定义名称空间。所以我仍然被困住了。
答案 0 :(得分:5)
您需要将专门化移动到BPCFGParser内部的内部类中。这样做符合两个要求
ActiveEquivClass
示例:
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;
};
答案 1 :(得分:1)
尝试移动哈希&lt;&gt; BPCFGParser类声明之前的模板特化代码。该错误意味着基于在/usr/include/c++/4.3/tr1_impl/functional_hash.h中定义的std :: hash扩展了哈希;因此,在实例化之前不使用您的专业化。理想情况下,在扩展模板之前,应该为编译器提供专业化代码。
答案 2 :(得分:0)
每当你使用一个类作为模板参数时,声明 该类必须完整,而不是简单地向前声明。
事实并非如此。模板参数何时必须是完整类型的限制通常取决于模板内容;但实例化具有不完整类型的模板并不违法,只要模板不包含非完整类型的代码即可。
解决问题的唯一方法是在类之前定义 specialization ,但是在类之后定义实际的成员函数operator()
。也就是说,
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 {
}
这也意味着没有嵌套类,因为你无法转发声明嵌套类。
答案 3 :(得分:0)
我遇到了完全相同的问题,最后提出了一个解决方法用户定义的哈希函子解决方案,见下文:
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;
};
我仍然想知道是否有std :: hash专业化方法。有人能想出来吗?
答案 4 :(得分:0)
我知道这个问题已经很老了,但我遇到了同样的问题,我想我会报告我的发现。
错误消息:
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>’
根本没有抱怨你的类,它说你不能专门化std :: hash,因为std :: hash的通用模板或现有的一个特化已经被使用 - 即有人使用过它在它被定义的点和你试图专门化的点之间。
this document的“详细信息”部分中有一些文字描述了这一点:
必须在第一次使用之前声明专业化 隐式实例化
在我的情况下,问题不在于我的专业化代码,问题在于它的位置。一旦使用了std :: hash,你就无法再对它进行专门化了。
我发现如果我在包含&lt; unordered_map&gt;之后立即将我的专业化代码移动到它,它就可以正常工作。
Puppy建议将专业化声明与实现分开,这使得您可以将声明移动到非常接近包含&lt; unordered_map&gt;的位置,实现可以在以后的任何地方进行(在BPCFGParser完全定义之后)情况)。
答案 5 :(得分:0)
如何在某个命名空间中定义成员类?
#include <unordered_map>
using std::unordered_map;
using std::hash;
namespace parser_detail
{
class ActiveEquivClass { };
class PassiveEquivClass { };
}
namespace std {
template <>
class hash<parser_detail::ActiveEquivClass>
{
public:
size_t operator()(const parser_detail::ActiveEquivClass & aec) const { return 0; }
};
template <>
class hash<parser_detail::PassiveEquivClass>
{
public:
size_t operator()(const parser_detail::PassiveEquivClass & aec) const { return 0; }
};
}
class BPCFGParser {
public:
class Edge { };
typedef parser_detail::ActiveEquivClass ActiveEquivClass;
typedef parser_detail::PassiveEquivClass PassiveEquivClass;
struct EqActiveEquivClass {
bool operator()(const ActiveEquivClass&, const ActiveEquivClass&) const { return false; }
};
struct EqPassiveEquivClass {
bool operator()(const PassiveEquivClass&, const PassiveEquivClass&) const { return false; }
};
unordered_map<ActiveEquivClass, Edge *, hash<ActiveEquivClass>, EqActiveEquivClass> discovered_active_edges;
unordered_map<PassiveEquivClass, Edge *, hash<PassiveEquivClass>, EqPassiveEquivClass> discovered_passive_edges;
};
int main() { }