gpt4 book ai didi

c++ - 模板运算符链接器错误

转载 作者:太空狗 更新时间:2023-10-29 20:31:59 24 4
gpt4 key购买 nike

我有一个链接器错误,我已简化为一个简单的示例。构建输出是:

debug/main.o: In function main':<br/>
C:\Users\Dani\Documents\Projects\Test1/main.cpp:5:
undefined reference to
log& log::operator<< (char const (&) [6])'
collect2: ld returned 1 exit status

链接器似乎忽略了 log.cpp 中的定义。
我也不能将定义放在 log.h 中,因为我多次包含该文件并且它提示重新定义。

主要.cpp:

#include "log.h"

int main()
{
log() << "hello";
return 0;
}

日志.h:

#ifndef LOG_H
#define LOG_H

class log
{
public:
log();
template<typename T>
log &operator <<(T &t);
};

#endif // LOG_H

日志.cpp:

#include "log.h"
#include <iostream>

log::log()
{
}

template<typename T>
log &log::operator <<(T &t)
{
std::cout << t << std::endl;
return *this;
}

最佳答案

我想这是您第一次使用模板,所以我会尽量说教。

您可以将模板视为某种类型感知宏。这种类型意识当然不容忽视,因为它免费授予类型安全。然而,这确实意味着模板函数或类不是函数或类:它们是将用于生成函数或类的模型。

例如:

template <class T>
void foo(T t) { std::cout << t << "\n"; }

这是一个模板函数,它允许我定义一些东西并将其应用于许多不同的类型。

int i;
foo(i); // [1]

这会导致 template 的实例化.基本上,这意味着根据模型创建了一个函数,但替换了所有出现的 T。通过 int .

double d;
foo(d); // Another instantiation, this time with `T` replaced by `double`
foo(d); // foo<double>() already exists, it's reused

现在,这个模型的想法非常重要。如果模型的定义不在头文件中,那么编译器就不知道如何定义方法。

所以,这里有 2 个解决方案:

  1. 在标题中定义
  2. 显式实例化它

两者有不同的用途。

(1) 是经典方式。它更容易,因为您不会将用户限制为类型的子集。但是,这确实意味着用户依赖于实现(更改它,她重新编译,并且您需要在 header 中提取依赖项)

(2) 较少使用。为了完全符合它要求的标准:

  • 您在 header (template <> void foo<int>();) 中声明特化,以便让编译器知道它存在
  • 您在链接的翻译单元之一中对其进行了完整定义

主要优点是,与经典函数一样,您可以将客户端与实现隔离开来。

gcc非常宽松,因为您可以放弃声明,它应该可以工作。

我还应该注意,可以使用不同的实现定义两次方法。这当然是一个错误,因为它直接违反了 ODR:一个定义规则。然而大多数链接器不报告它,因为每个对象有一个实现是很常见的,他们只是选择第一个并假设其他的是等效的(这是模板的特殊规则)。因此,如果您确实想使用显式实例化,请务必只定义一次。

关于c++ - 模板运算符链接器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3007251/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com