LNK4221: operator<< 重载未在静态库中导出

LNK4221: operator<< overload not exported in static library

尽管有很多关于类似主题的问题,但我找不到能解决我的问题的问题。

我正在使用 Visual Studio 2013 社区版。我有一个包含两个项目的解决方案。一个项目被编译为静态库,另一个是应用程序。应用依赖静态库,编译运行正常

一个 class(.cpp/.h 对),特别是 Ref,被链接器忽略(来源列在底部)。从我的编译输出来看,ref.cpp 是在 namespace.cpp 之前编译的。 namespace.cpp 间接包含 ref.h,可能导致链接器的先进后出行为忽略 Ref ?

我在 ref.cpp 和 ref.h 中都有一个运算符 << 的重载。为什么好像被忽略了?

warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library  [...]Omni\Core\ref.obj  Core

ref.h

#ifndef REF_H
#define REF_H

#include <memory>
#include <ostream>

namespace Omni
{
    template<typename T>
    using Ref = std::shared_ptr<T>;
}

template<typename T>
std::ostream & operator<<(std::ostream & s, const Omni::Ref<T> type);

#endif // REF_H

(我知道 using namespace Omni; 排除了 Omni:: 的需要,但在调试时我喜欢双重确定。)

ref.cpp

#include "ref.h"

using namespace Omni;

template<typename T>
std::ostream & operator<<(std::ostream & s, const Omni::Ref<T> value)
{
    return s << *value;
}

啊,我可以看到你做了什么。您认为 ref.cpp 中的函数定义实际上并不是函数定义(即它不生成代码)。它只是一个 模板 函数定义。

为了让这个模板引起代码的生成,你必须实际引用一个模板函数的具体例子。

但是当然在你的 ref.cpp 中没有任何地方这样做,所以当编译 ref.cpp 时没有实例化 operator<<(std::ostream&, const Omni::Ref<T>) 的具体例子。

当您的客户端代码在 Omni::Ref<T> 上为任何 T 调用 operator<< 时,它会完美地生成调用站点代码,因为有模板原型,但没有信息实际创建函数的实现 - 在 ref.cpp 中,客户端代码不可用。

解决方法: 将模板函数的定义放在头文件中。