实例化后模板的特化?

发布于 2024-08-14 11:06:19 字数 3125 浏览 2 评论 0原文

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

帅气尐潴 2024-08-21 11:06:19

您需要将专业化移至 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;

};

You need to move the specialization into an inner class inside of BPCFGParser. Doing so meets both requirements

  1. Specialization is after the complete definition of ActiveEquivClass
  2. Before the use of the specialization

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;

};
半山落雨半山空 2024-08-21 11:06:19

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

错误消息:

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 被完全使用,你就不能再进一步专门化它了。

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

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:

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).

ま昔日黯然 2024-08-21 11:06:19

尝试将哈希移动<> 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.

稀香 2024-08-21 11:06:19

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

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

解决问题的唯一方法是在类之前定义专门化,但在类之后定义实际的成员函数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 {
}

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

Whenever you use a class as a template parameter, the declaration of
that class must be complete and not simply forward declared.

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,

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

This also means, no nested classes, as you cannot forward declare a nested class.

怎樣才叫好 2024-08-21 11:06:19

我有完全相同的问题,最后想出了一个解决方法用户定义的哈希函子解决方案,请参见下文:

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 专门化方法。有人能弄清楚吗?

I've exactly the same problem and finally come up with a workaround user-defined hash functor solution, see below:

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

And I'm stil wondering whether there's a std::hash specialization approach. Can anyone figure it out?

小瓶盖 2024-08-21 11:06:19

在某个命名空间中定义成员类怎么样?

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

What about define the member classes in a certain namespace?

#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() { }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文