命名空间中函数专用化的未定义引用

Undefined reference for function specialization in namespace

提问人:DragonDePlatino 提问时间:4/5/2021 更新时间:4/5/2021 访问量:158

问:

我正在实现一个以 .对于要序列化的每种类型,定义一个接受存档和对象的非侵入式函数:boost::archive

// archive.hpp
#pragma once

namespace Archive {
    template <class A, class T>
    void serialize(A& a, T& value);
}

struct ArchiveOut {
    void add(const char* key, int& value) {}

    // ... Implementations for basic types ...

    template <class T>
    void add(const char* key, T& value) {
        ArchiveOut archive;
        Archive::serialize(archive, value);
    }
};
// main.cpp
#include "archive.hpp"

struct Child {
    int id;
};

struct Parent {
    int id;
    Child child;
};

template <class A>
void Archive::serialize(A& a, Parent& v) {
    a.add("id", v.id);
    a.add("child", v.child);
}

template <class A>
void Archive::serialize(A& a, Child& v) {
    a.add("id", v.id);
}

int main() {
    Parent parent;
    ArchiveOut archive;
    Archive::serialize(archive, parent);
}

目前,该系统适用于复杂的嵌套类型,但前提是它位于全局命名空间中。一旦它被移动到命名空间中,我就会收到一个链接器错误:serializeArchive

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\DDP\AppData\Local\Temp\ccMWEvEu.o:test.cpp:(.text$_ZN10ArchiveOut3addI5ChildEEvPKcRT_[_ZN10ArchiveOut3addI5ChildEEvPKcRT_]+0x20): undefined reference to `void Archive::serialize<ArchiveOut, Child>(ArchiveOut&, Child&)

我知道我的专长有正确的签名,因为它们与助推器相匹配,但也许我最初的原型是错误的?我尝试过挖掘升压内部结构,但找不到初始原型的位置。我还检查了其他答案,所有这些答案都与与函数签名不匹配或未将其放置在正确的命名空间中的专业化有关。我能得到关于这种链接器行为的解释吗?serialize

C 模板 命名空间 G++ 未定义引用

评论

0赞 cigien 4/5/2021
看起来您正在尝试部分专用化函数模板。这实际上是不可能的。
0赞 DragonDePlatino 4/5/2021
我想,那么像boost这样的东西是如何定义初始函数原型的,以便它允许这样的专业化呢?为什么它在全局命名空间中起作用?
1赞 cigien 4/5/2021
请参阅中的第 2 层注释“注意使用函数重载来补偿 C++ 当前不支持函数模板的部分模板专用化”。他们使用第三个参数来获得这种效果。他们做了更多的事情来处理以不同方式进行 2 阶段查找的编译器。恐怕在你让你的版本表现得像 Boost 之前,还有很多事情要弄清楚。const unsigned int

答:

0赞 max66 4/5/2021 #1

您正在需要部分专业化的地方使用重载。

问题在于函数不能部分专用化。

建议:在部分专用结构中使用静态函数。

内容如下(注意:代码未测试)

// archive.hpp

namespace Archive {
    template <typename A, typename T>
    struct serial;

    template <class A, class T>
    void serialize(A& a, T& value)
     { serial<A, T>::func(a, value); }
}

// main.cpp
#include "archive.hpp"

// ...

namespace Archive {

   template <class A>
   struct serial<A, Parent>
    {
      static void func (A & a, Parent & v)
       {
         a.add("id", v.id);
         a.add("child", v.child);
       }
    };  

   template <class A>   
   struct serial<A, Child>
    {
      static void func (A & a, Child & v)
       { a.add("id", v.id); }
    };
 }