【发布时间】:2015-11-11 18:21:27
【问题描述】:
为了减少继承,我正在跳槽。
我读过一个类似的问题here。它显示了如何使用基类解决问题。我尝试放开继承,所以我正在寻找不同的东西——更多地沿着注释线。
我创建并编译了一个具有一种专业化的模板类 (normal)。需要模板的方法在标头(Mixer.hpp)中。不需要模板的方法在cpp文件中(Mixer.cpp)。当编译成静态库时,cpp 部分仅被编译为一种特化 (Mixer<normal>)。编译器当时不知道 (awsome)。将生成的静态库导入另一个项目并尝试创建不同的泛型 (awsome) 类会导致链接器错误,因为显然该库不包含该方法标识符 (Mixer<awesome>::noTemplateInvolved)。然而,正常实现的代码与任何代码一样好,因此链接器实际上可以链接到其他模板版本的现有源代码 (Mixer<?dontcare?>::noTemplateInvolved)。编译器所要做的就是为链接器适当地标记它。
这是导致链接器错误的源代码:
//Target compiled to Provider.lib
//Mixer.hpp
#pragma once
#include <iostream>
using namespace std;
struct normal { static void log() { cout << "normal\n"; } };
template<typename output = normal>
class Mixer
{
public:
void callingTemplate();
void noTemplateInvolved();
};
template<typename output>
void Mixer<output>::callingTemplate() { output::log(); }
//Mixer.cpp
#include "Mixer.hpp"
void Mixer<>::noTemplateInvolved()
{
cout << "noTemplateInvolved\n";
}
//Target Compiled to User.exe
//This target imports Provider.lib
#include <Provider\Mixer.hpp>
#pragma comment(lib, "Provider.lib")
struct awsome { static void log() { cout << "awsome\n"; } };
int main()
{
Mixer<> n;
n.callingTemplate();
n.noTemplateInvolved();
Mixer<awsome> a;
a.callingTemplate();
a.noTemplateInvolved(); //linker error here
return 0;
}
类Mixer<awsome> 可以链接到方法callingTemplate,因为它的定义在头文件中并且编译器会创建该函数。在User.exe 编译时,noTemplateInvolved 的定义对编译器是隐藏的。编译器无法创建该方法并且链接必须失败。
我知道三种解决方案。
- 将
noTemplateInvolved的定义移到标题中。 - 包含 cpp 文件
- 从基类继承
我正在寻找另一种解决方案。 noTemplateInvolved 的正文确实与模板无关。我想在标题中注释方法。我希望编译器知道无论模板如何,它都应该始终使用相同的基本实现。
这可能吗?
编辑:在开头稍微注释了那个无聊的段落。
【问题讨论】:
-
如果它与模板无关,为什么它是一个成员,而且是非静态的?您可以将它实现为一个单独的、非模板的非成员函数,并且可能只有一个成员存根转发给它——您必须提供存根的定义,但这只是很可能的一行内联。这是你要找的东西吗?无论如何,我不确定您为什么不想选择非依赖基础解决方案;也许在问题中解释这个决定会更清楚地说明您的要求。
-
您可以使用显式模板实例化。为什么你不想移动非模板函数到基类?在这种情况下,它没有开销。
-
最终目标是重构。如果我可以在标题中注释某些内容,我就不必触及实现。如果不出意外,这对我来说是有教育意义的。显式实例化在所呈现的情况下不起作用 - 在已知“struct awsome”之前编译库。尽管我认为它已被弃用,但我会尝试使用 extern 关键字。
-
在我的实际生产代码中,我转而使用基类,但是我确实有另一个想法,我将很快实现,看看这是否能让我更接近注释表单。
标签: c++ templates static-libraries