在匿名命名空间中定义模板特化(以及编译错误 C2888)

Defining a template specialization in an anonymous namespace (and compile error C2888)

简而言之版本: 为什么我不能在该编译内的匿名命名空间中定义仅在当前编译单元中有用的模板特化(std-lib 类型)单元/cpp 文件?

更长的版本:

我有一个类型,它只是一个 cpp 文件中的快速助手,我们称它为 struct Helper。因为它只在该编译单元中使用,所以它是在 cpp 内部的匿名命名空间中声明和定义的。

因为我想要std::unordered_set<Helper>,所以我必须专攻std::hash。当我现在尝试在同一个匿名命名空间中定义它时,我得到一个 C2888 'std::hash<'anonymous-namespace'::Helper>': symbol cannot be defined within namespace 'anonymous-namespace'。这是为什么?

我也尝试在 AN 中添加 using namespace std 和类似的东西,但无济于事。

/* This doesn't work */

namespace
{
    struct Helper
    {
        int member1;
        bool member2;
    };

    using namespace std;
    template<>
    struct std::hash<Helper>
    {
        size_t operator()(const Helper& helper) const
        {
            return 12345; /* how it's really generated is irrelevant here */
        }
    };
}

当然,我可以将专业化放在 AN 之外,这样就可以了。我只是想了解为什么它在里面时不会

/* This works, but why doesn't the other? */

namespace
{
    struct Helper
    {
        int member1;
        bool member2;
    };
}

template<>
struct std::hash<Helper>
{
    size_t operator()(const Helper& helper) const
    {
        return 12345; /* how it's really generated is irrelevant here */
    }
};

属于命名空间 std 的符号必须在包含 std 的命名空间中定义,这意味着您必须在全局命名空间中定义它。

这是来自 C2888 的示例:

namespace M {
   namespace N {
      void f1();
      void f2();
   }

   void N::f1() {}   // OK: namspace M encloses N
}

namespace O {
   void M::N::f2() {}   // C2888 namespace O does not enclose M
}

[temp.expl.spec/9] 来自 C++20 草案:

A template explicit specialization is in the scope of the namespace in which the template was defined. [ Example:

namespace N {
  template<class T> class X { /* ... */ };
  template<class T> class Y { /* ... */ };

  template<>
  class X<int> { /* ... */ };     // OK: specialization in same namespace

  template<>
  class Y<double>;                // forward-declare intent to specialize for double
}

template<>
class N::Y<double> { /* ... */ }; // OK: specialization in enclosing namespace

template<>
class N::Y<short> { /* ... */ };  // OK: specialization in enclosing namespace

— end example ]