Dan*_*ani 4 c++ linker templates
我有一个链接器错误,我已将其简化为一个简单的示例。构建输出是:
debug/main.o: 在函数log& log::operator<< (char const (&) [6])' collect2: ld 返回 1 退出状态
main':
C:\Users\Dani\Documents\Projects\Test1/main.cpp:5: undefined reference to
看起来链接器忽略了 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) 较少使用。为了完全符合该标准,它需要:
template <> void foo<int>();以便让编译器知道它存在主要优点是,与经典函数一样,您可以将客户端与实现隔离。
gcc是相当宽松的,因为你可以放弃声明,它应该可以工作。
我还应该注意到,可以用不同的实现来定义一个方法两次。这当然是一个错误,因为它直接违反了 ODR:单一定义规则。然而,大多数链接器不会报告它,因为每个对象都有一个实现是很常见的,并且它们只是选择第一个并假设其他实现是等效的(这是模板的特殊规则)。因此,如果您确实想使用显式实例化,请务必小心,仅定义一次。