模板操作员链接器错误 [英] Template operator linker error

查看:83
本文介绍了模板操作员链接器错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a linker error I've reduced to a simple example. The build output is:


debug / main.o:在函数 main':

C:\Users\Dani\Documents\Projects\Test1 / main.cpp:5:
未定义引用
log&
log :: operator<< (char
const(&)[6])'

collect2:ld返回
1退出状态

debug/main.o: In function main':
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中,因为我包含了多次的文件,它抱怨重定义。

It looks like the linker ignores the definition in log.cpp.
I also cant put the definition in log.h because I include the file alot of times and it complains about redefinitions.

main.cpp:

#include "log.h"

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

log.h:

#ifndef LOG_H
#define LOG_H

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

#endif // LOG_H

log.cpp:

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

log::log()
{
}

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


推荐答案

使用模板,所以我会尽量做教学。

I guess this is your first use of templates, so I'll try to be didactic.

你可以认为模板是某种类型感知的宏。这种类型的意识当然不能被忽略,因为它免费提供类型安全。这并不意味着模板函数或类不是函数或类:它们是将用于生成函数或类的模型。

You can think of template as some kind of type-aware macros. This type awareness is of course not to be neglected, since it grants type safety for free. This does mean however than template functions or classes are NOT functions or classes: they are model that will be used to generate functions or classes.

例如:

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

这是一个模板函数,它允许我定义一次并应用于许多不同类型。

This is a template function, it allows me to define something once and apply it to many different types.

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

这会导致模板。基本上,这意味着根据模型创建一个函数,但用 int 替换 T 的所有出现。 / p>

This causes the instantiation of the template. Basically, it means that a function is created according to the model, but replacing all occurrences of T by int.

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

重要。如果模型的定义不存在于头文件中,那么编译器不知道如何定义方法。

Now, this idea of model is very important. If the definition of the model is not present in the header file, then the compiler does not know how to define the method.

所以,这里有两个解决方案: / p>

So, you have 2 solutions here:


  1. 在标题中定义

  2. 显式实例化



    2有不同的用途。

The 2 have different uses.

(1)是经典的方式。它更容易,因为你不限制用户的类型的一个子集。但是,这的确意味着用户依赖于实现(改变它,她重新编译,并且你需要拉头的依赖)

(1) is the classic way. It's easier because you don't restrict the user to a subset of the types. However it does mean that the user depends on the implementation (change it, she recompiles, and you need to pull the dependencies in the header)

(2)较少用过的。要完全符合标准,需要:

(2) is less often used. For full compliance with the standard it requires:


  • 您在标题中声明了特殊化( template< ;

  • 在一个翻译单元中完全定义它
  • / li>
  • That you declare the specialization in the header (template <> void foo<int>();) so as to let the compiler know it exists
  • That you fully define it in one of the translation units linked

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

The main advantage is that, like classic functions, you isolate the client from the implementation.

gcc 是相当宽松的,因为你可以放弃声明,它应该工作。

gcc is quite lenient because you can forgo the declaration and it should work.

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

I should also note that it is possible to define a method twice, with different implementations. This is of course an error, as it is in direct violation of the ODR: One Definition Rule. However most linkers don't report it because it's quite common to have one implementation per object, and they just pick the first and assume the others will be equivalent (it's a special rule for templates). So if you do want to use explicit instantiation, take great care to only define it once.

这篇关于模板操作员链接器错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆