模板 class 具有不使用模板的函数
template class with functions that do not use the template
我正在努力减少继承。
我看过一个类似的问题here。它显示了如何使用基础 class 解决问题。我试图松散继承,所以我正在寻找不同的东西——更多的是注释。
我创建并编译了一个模板 class,具有一个专业化 (normal
)。需要模板的方法在 header (Mixer.hpp
) 中。不需要模板的方法在cpp文件中(Mixer.cpp
)。当编译成静态库时,cpp 部分只被编译为一个专业化 (Mixer<normal>
)。编译器当时不知道 (awsome
)。将生成的静态库导入另一个项目并尝试创建不同的泛型 (awsome
) class 会导致 linker 错误,因为显然该库不包含该方法标识符 (Mixer<awesome>::noTemplateInvolved
).然而,正常实现的代码与任何代码一样好,所以 linker 可以 link 到其他模板版本 (Mixer<?dontcare?>::noTemplateInvolved
) 的现有源代码。编译器所要做的就是为 linker.
适当地标记它。
这是导致 linker 错误的源代码:
//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;
}
class Mixer<awsome>
可以 link 方法 callingTemplate
因为它的定义在 header 中并且编译器创建该函数。在 User.exe
编译时,noTemplateInvolved
的定义对编译器是隐藏的。编译器无法创建该方法,linking 必须失败。
我知道三种解决方案。
- 将
noTemplateInvolved
的定义移动到 header。
- 包含 cpp 文件
- 从基础继承class
我正在寻找另一种解决方案。 noTemplateInvolved
的 body 真的和模板没有关系。我想在 header 中注释该方法。我希望编译器知道它应该始终使用相同的基本实现,而不管模板如何。
这可能吗?
编辑:在开头对那个无聊的段落做了一点注释。
答案原来是评论中建议的基础class。我想要 base class 的原因之一是我不想重构。使用基class重构其实很简单。
将 original
class 重命名为 original_base
。
继承自 original_template
继承自 original_base
。确保复制构造函数并将所有参数传递给基 class。
语句 using original = original_template<your default case here>
确保还没有其他源代码需要修改。
应用到上面的例子我最终做了这样的事情:
//Target compiled to Provider.lib
//Mixer.hpp
#pragma once
#include <iostream>
using namespace std;
struct normal { static void log() { cout << "normal\n"; } };
class Mixer_Base
{
private:
int mixcount;
public:
Mixer_Base(int count);
void noTemplateInvolved();
};
template<typename output = normal>
class Mixer_tempalte : public Mixer_Base
{
public:
Mixer_tempalte(int count) : Mixer_Base(count)
{}
void callingTemplate();
};
template<typename output>
void Mixer_tempalte<output>::callingTemplate()
{
output::log();
}
using Mixer = Mixer_tempalte<>;
//Mixer.cpp
#include "Mixer.hpp"
void Mixer_Base::noTemplateInvolved()
{
cout << "noTemplateInvolved\n";
}
Mixer_Base::Mixer_Base(int count) : mixcount(count)
{}
//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(4);
n.callingTemplate();
n.noTemplateInvolved();
Mixer_tempalte<awsome> a(3);
a.callingTemplate();
a.noTemplateInvolved();
return 0;
}
在某种程度上,注释感觉就像基础 class 感觉一样。基础 class 中的所有内容现在都按照我想要的方式进行注释,尽管这不会减少继承。
我正在努力减少继承。
我看过一个类似的问题here。它显示了如何使用基础 class 解决问题。我试图松散继承,所以我正在寻找不同的东西——更多的是注释。
我创建并编译了一个模板 class,具有一个专业化 (normal
)。需要模板的方法在 header (Mixer.hpp
) 中。不需要模板的方法在cpp文件中(Mixer.cpp
)。当编译成静态库时,cpp 部分只被编译为一个专业化 (Mixer<normal>
)。编译器当时不知道 (awsome
)。将生成的静态库导入另一个项目并尝试创建不同的泛型 (awsome
) class 会导致 linker 错误,因为显然该库不包含该方法标识符 (Mixer<awesome>::noTemplateInvolved
).然而,正常实现的代码与任何代码一样好,所以 linker 可以 link 到其他模板版本 (Mixer<?dontcare?>::noTemplateInvolved
) 的现有源代码。编译器所要做的就是为 linker.
这是导致 linker 错误的源代码:
//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;
}
class Mixer<awsome>
可以 link 方法 callingTemplate
因为它的定义在 header 中并且编译器创建该函数。在 User.exe
编译时,noTemplateInvolved
的定义对编译器是隐藏的。编译器无法创建该方法,linking 必须失败。
我知道三种解决方案。
- 将
noTemplateInvolved
的定义移动到 header。 - 包含 cpp 文件
- 从基础继承class
我正在寻找另一种解决方案。 noTemplateInvolved
的 body 真的和模板没有关系。我想在 header 中注释该方法。我希望编译器知道它应该始终使用相同的基本实现,而不管模板如何。
这可能吗?
编辑:在开头对那个无聊的段落做了一点注释。
答案原来是评论中建议的基础class。我想要 base class 的原因之一是我不想重构。使用基class重构其实很简单。
将 original
class 重命名为 original_base
。
继承自 original_template
继承自 original_base
。确保复制构造函数并将所有参数传递给基 class。
语句 using original = original_template<your default case here>
确保还没有其他源代码需要修改。
应用到上面的例子我最终做了这样的事情:
//Target compiled to Provider.lib
//Mixer.hpp
#pragma once
#include <iostream>
using namespace std;
struct normal { static void log() { cout << "normal\n"; } };
class Mixer_Base
{
private:
int mixcount;
public:
Mixer_Base(int count);
void noTemplateInvolved();
};
template<typename output = normal>
class Mixer_tempalte : public Mixer_Base
{
public:
Mixer_tempalte(int count) : Mixer_Base(count)
{}
void callingTemplate();
};
template<typename output>
void Mixer_tempalte<output>::callingTemplate()
{
output::log();
}
using Mixer = Mixer_tempalte<>;
//Mixer.cpp
#include "Mixer.hpp"
void Mixer_Base::noTemplateInvolved()
{
cout << "noTemplateInvolved\n";
}
Mixer_Base::Mixer_Base(int count) : mixcount(count)
{}
//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(4);
n.callingTemplate();
n.noTemplateInvolved();
Mixer_tempalte<awsome> a(3);
a.callingTemplate();
a.noTemplateInvolved();
return 0;
}
在某种程度上,注释感觉就像基础 class 感觉一样。基础 class 中的所有内容现在都按照我想要的方式进行注释,尽管这不会减少继承。