实例化后模板的特化?

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的一个回答中,有人声称无法在类内定义命名空间。所以我还是卡住了。

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;

};

非常感谢您的回答,但它并没有起作用。请看下面的解释。 - Onur Cobanoglu

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或现有的某个专门化 - 也就是说,在定义它和你尝试专门化它之间的某个点上,有人已经使用了它。

this document的“详细信息”部分中有一些描述:

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

在我的情况下,问题不在于我的专门化代码,而在于其位置。一旦std::hash被使用,就无法进一步专门化它。

我发现,如果我将我的专门化代码移动到包括<unordered_map>之后,它就可以正常工作。

Puppy建议将专门化的声明与实现分开,这样可以将声明移到包括<unordered_map>的位置附近,实现可以稍后放在方便的地方(在您的情况下,在BPCFGParser完全定义之后)。


1
尝试将hash<>模板特化代码移动到BPCFGParser类声明之前。该错误意味着hash是基于在/usr/include/c++/4.3/tr1_impl/functional_hash.h中定义的std::hash进行扩展的;因此,在实例化之前不会使用您的特化。理想情况下,应该在模板扩展之前使编译器能够使用您的特化代码。

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 {
}

这也意味着,没有嵌套类,因为你不能前向声明一个嵌套类。

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特化的方法。有人能搞清楚吗?


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() { }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接