10

我的完整代码太长了,但这里有一个片段可以反映我的问题的本质:

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中给出的答案中,有人声称不能在类中定义命名空间。所以我还是卡住了。

4

6 回答 6

7

您需要将专业化移动到 BPCFGParser 内部的内部类中。这样做符合这两个要求

  1. 专业化是在完整定义之后ActiveEquivClass
  2. 使用专业之前

例子:

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;

};
于 2009-12-12T20:02:10.473 回答
2

我知道这个问题已经很老了,但我刚刚遇到了同样的问题,我想我会报告我的发现。

错误信息:

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 的通用模板或现有的专业化之一已经被使用 - 即有人在指出它已被定义以及您尝试对其进行专门化的点。

在本文档的“详细”部分中有一些文字描述了这一点:

必须在第一次使用之前声明会导致隐式实例化的特化

就我而言,问题不在于我的专业化代码,而在于它的位置。一旦完全使用了 std::hash ,您就无法进一步对其进行专门化。

我发现如果我在包含 <unordered_map> 之后立即将我的专业化代码移动到,它工作得很好。

Puppy 将专业化声明与实现分开的建议允许您将声明移动到非常接近包含 <unordered_map> 的位置,实现可以在方便的地方稍后出现(在您的案例中完全定义 BPCFGParser 之后)。

于 2016-03-04T17:05:31.740 回答
1

尝试在 BPCFGParser 类声明之前移动 hash<> 模板特化代码。该错误意味着哈希是根据 /usr/include/c++/4.3/tr1_impl/functional_hash.h 中定义的 std::hash 扩展的;因此,在实例化之前不使用您的专业化。理想情况下,您的专业化代码应该在模板展开之前可供编译器使用。

于 2010-04-13T07:59:52.590 回答
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 专业化方法。任何人都可以弄清楚吗?

于 2013-09-18T13:27:27.530 回答
0

每当您使用一个类作为模板参数时,该类的声明必须是完整的,而不是简单地向前声明。

这实际上不是真的。模板参数何时必须是完整类型的限制通常取决于模板内容;但是,只要模板不包含不完整类型的非法代码,实例化具有不完整类型的模板并不违法。

解决问题的唯一方法是在类之前定义特化,但在类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 {
}

这也意味着没有嵌套类,因为您不能转发声明嵌套类。

于 2012-05-09T00:43:39.450 回答
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() { }
于 2020-04-24T13:08:20.183 回答