请考虑以下标头和源文件:
// main.cpp
#include "myClass.h"
int main()
{
MyClass m;
m.foo<double>();
m.foo<float>();
}
Run Code Online (Sandbox Code Playgroud)
// myClass.h
#pragma once
#include <iostream>
using namespace std;
class MyClass
{
public:
template <typename T>
void foo()
{
cout << "Template function<T> called" << endl;
}
template <>
void foo<int>()
{
cout << "Template function<int> called" << endl;
}
template <>
void foo<float>();
};
Run Code Online (Sandbox Code Playgroud)
// myClass.cpp
#include "myClass.h"
template <>
void MyClass::foo<float>()
{
cout << "Template function<float> called" << endl;
}
Run Code Online (Sandbox Code Playgroud)
我得到了foo<float>专业化的链接错误.如果我将专门化的定义放在头文件中,那么一切都按预期工作.
我认为原因可能是该方法未被显式实例化(尽管完全特template …
请参阅此问题中有关实施模板的第一个答案.
具体来说,请注意这个引用
一个常见的解决方案是在头文件中编写模板声明,然后在实现文件(例如.tpp)中实现该类,并在头的末尾包含此实现文件.
我加粗了我最感兴趣的部分
..tpp文件的意义是什么?我尝试完全按照该页面中的建议进行操作.但后来,我将文件扩展名更改为任何随机乱码(如.zz或.ypp),它仍然有效!它应该工作吗?是否.tpp或任何其他扩展名是否重要?为什么不使用.cpp?
这是我很困惑的另一件事.
如果我的实现是用.cpp编写的,并且头文件定义了非模板化的函数,那么我只需要编译一次.cpp文件,对吧?至少在我改变.cpp文件中的内容之前.
但是,如果我有一个定义模板化函数的标题,并且我的实现是在一个带有随机时髦扩展的文件中,它是如何编译的?每次编译任何源代码#include的头部时,编译的实现是什么?
可以像这样声明main函数:
template<typename T1, typename T2>
int main(T1 argc, T2 *argv[])
{
}
Run Code Online (Sandbox Code Playgroud)
对于实例化T1= int和T2= char我们最终得到一个共同的签名.
main没有提及模板的限制:
程序中没有其他功能可以称为main
main不能定义为内联或静态.
无法从程序中调用C++ main.
C++不能采用main的地址.
C++主函数不能重载.
显然没有这种语法的应用,但是
在我第一次尝试上述问题时,我有点模糊.(正确地)对这个问题有一些否定的评论,所以我应该就要求就这个主题提出反馈做出一些推理:
C++是一种不断发展的语言,也许这是实现的,有人意识到它
有人可以告诉我为什么 main它有限制
语言律师可以在标准中找到一个漏洞来允许这样的声明(恰好相反)
模块系统的发展将语言推向了组件分离的逻辑(就目前的编译单元而言).也许这会影响我们生成编译单元的方式,也许main在子模块中定义多个函数,在这种情况下需要更灵活的 main.
main如果标准允许类似的东西(将来)我们可以写
template<typename... Args>
int main(Args&& ...vs)
{
}
Run Code Online (Sandbox Code Playgroud)
你去,安全的命令行参数解析(我发明了轮子还是什么?)
假设我有一个标题wrapper.h:
template <typename Func> void wrapper(const Func func);
Run Code Online (Sandbox Code Playgroud)
和一个文件wrapper.cpp包含:
#include "wrapper.h"
template <typename Func>
void wrapper(const Func func)
{
func();
}
Run Code Online (Sandbox Code Playgroud)
并且文件main.cpp包含:
#include "wrapper.h"
#include <iostream>
int main()
{
wrapper( [](){std::cout<<"hello."<<std::endl;} );
}
Run Code Online (Sandbox Code Playgroud)
如果我一起编译这些(例如cat wrapper.cpp main.cpp | g++ -std=c++11 -o main -x c++ -),我没有链接器错误.
但是如果我单独编译它们(例如g++ -std=c++11 -o wrapper.o -c wrapper.cpp && g++ -std=c++11 -o main main.cpp wrapper.o),我当然---得到一个链接器错误:
Undefined symbols for architecture x86_64:
"void wrapper<main::$_0>(main::$_0)", referenced from:
_main in …Run Code Online (Sandbox Code Playgroud) 我想实例化
template<typename T> void foo(
T& t,
SomeType some_parameter,
AnotherType another_parameter,
EtcType yet_another_parameter,
AsYouCanTell this_is_a_very_long_signature);
Run Code Online (Sandbox Code Playgroud)
也就是说,具有长签名的函数.现在,我知道如何做到这一点:
template void foo<int>(
int& t,
SomeType some_parameter,
AnotherType another_parameter,
EtcType yet_another_parameter,
AsYouCanTell this_is_a_very_long_signature);
Run Code Online (Sandbox Code Playgroud)
但我必须复制签名.此外,如果想要5种不同类型的特定实例化,我会复制5次吗?没有意义......
我想也许我可以写
template decltype(foo<int>);
Run Code Online (Sandbox Code Playgroud)
但由于某种原因,这不起作用.为什么?
由于某种原因,此文件中定义的符号之一未显示在目标文件中:
/**
* || File: random.cc
* || Project: Shatter
* || Encoding: UTF-8
* || Author: ********
*
* Copyright (C) 2016 ********** *. ****
* All rights reserved.
* Use by explicit written permission only.
*
* Changelog:
* - Aug 24, 2016, 07:35:22 PM --- File was created by ********
*
*/
#include <shatter/random/random.h>
// @TODO: MOVE TO <config-build.h>
#define _M_FEATURE_ARC4RANDOM
#ifdef _M_FEATURE_ARC4RANDOM
#define RAND_SEED (arc4random())
#define RAND_IMPL (rand())
#else
#include <time.h>
#define RAND_SEED (time(NULL))
#define RAND_IMPL …Run Code Online (Sandbox Code Playgroud)