实例化后模板的特化?
我的完整代码太长,但这里有一个片段反映了我的问题的本质:
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,有人声称命名空间不能在类中定义。所以我还是被困住了。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您需要将专业化移至 BPCFGParser 内部的内部类中。这样做满足了两个要求
ActiveEquivClass
完整定义之后示例:
You need to move the specialization into an inner class inside of BPCFGParser. Doing so meets both requirements
ActiveEquivClass
Example:
我知道这个问题已经很老了,但我刚刚遇到了同样的问题,我想我应该报告我的发现。
错误消息:
根本不是抱怨你的类,而是说你不能专门化 std::hash 因为 std::hash 的通用模板或现有的专门化之一已经被使用 - 即有人已经使用了在它被定义的点和你试图专门化它的点之间使用它。
本文档的“详细”部分有一些文字对此进行了描述:
在我的例子中,问题不在于我的专业化代码,问题在于它的位置。一旦 std::hash 被完全使用,你就不能再进一步专门化它了。
我发现如果我在包含之后立即将我的专业化代码移至,它工作得很好。
Puppy 建议将专门化的声明与实现分开,允许您将声明移动到非常接近包含的位置,实现可以在方便的地方稍后进行(在您的情况下完全定义 BPCFGParser 之后)。
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:
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:
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).
尝试将哈希移动<> BPCFGParser 类声明之前的模板专业化代码。该错误意味着 hash 是基于 /usr/include/c++/4.3/tr1_impl/featured_hash.h 中定义的 std::hash 进行扩展的;因此,在实例化之前不会使用您的专业化。理想情况下,您的专业化代码应该在扩展模板之前可供编译器使用。
Try moving the hash<> template specialization code before the BPCFGParser class declaration. The error means that hash is expanded based on std::hash defined at /usr/include/c++/4.3/tr1_impl/functional_hash.h; So your specialization is not used before the instantiation. Ideally, your specialization code should be made available for the compiler before the template is expanded.
这实际上不是真的。模板参数何时必须是完整类型的限制通常取决于模板内容;但是,只要模板不包含非法的不完整类型的代码,则实例化具有不完整类型的模板并不违法。
解决问题的唯一方法是在类之前定义专门化,但在类之后定义实际的成员函数operator()。 。也就是说,
这也意味着没有嵌套类,因为您不能转发声明嵌套类。
This is not actually true. The limitations of when template parameters have to be complete types is generally dependent on the template contents; but it is not illegal to instantiate a template with an incomplete type as long as the template does not contain code that is illegal with an incomplete type.
The only way to approach your problem is to define the specialization before the class, but to define the actual member function
operator()
after the class. That is,This also means, no nested classes, as you cannot forward declare a nested class.
我有完全相同的问题,最后想出了一个解决方法用户定义的哈希函子解决方案,请参见下文:
而且我仍然想知道是否有 std::hash 专门化方法。有人能弄清楚吗?
I've exactly the same problem and finally come up with a workaround user-defined hash functor solution, see below:
And I'm stil wondering whether there's a std::hash specialization approach. Can anyone figure it out?
在某个命名空间中定义成员类怎么样?
What about define the member classes in a certain namespace?