【发布时间】:2021-06-30 23:13:52
【问题描述】:
我正在实现一个以boost::archive 为模型的 JSON 存档系统。对于您想要序列化的每种类型,您定义一个接受存档和您的对象的非侵入式函数:
// 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);
}
目前,系统适用于复杂的嵌套类型,但前提是 serialize 位于全局命名空间中。一旦它被移动到 Archive 命名空间中,我会收到一个链接器错误:
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&)
我知道我的专业具有正确的签名,因为它们与 boost 匹配,但也许我的初始原型是错误的?我尝试过挖掘 boost 内部结构,但找不到最初的 serialize 原型在哪里。我还检查了其他答案,所有这些都与不匹配函数签名或未将其放置在正确命名空间中的专业化有关。我能解释一下这个链接器的行为吗?
【问题讨论】:
-
您似乎正在尝试对函数模板进行部分特化。这实际上是不可能的。
-
我想,那么像 boost 之类的东西是如何定义初始函数原型的,以便允许这样的专业化?为什么它可以在全局命名空间中工作?
-
参见source 中的第 2 层 cmets“注意使用函数重载来弥补 C++ 目前不支持函数模板的部分模板特化”。他们使用第三个
const unsigned int参数来获得这种效果。他们还做更多的事情来处理以不同方式进行两阶段查找的编译器。恐怕要让你的版本表现得像 Boost 一样,还有很多事情要弄清楚。
标签: c++ templates namespaces g++ undefined-reference