【问题标题】:Forward declaration of a template function from a seperate file从单独的文件中前向声明模板函数
【发布时间】:2017-01-15 22:49:40
【问题描述】:

其他.cpp

#include <iostream>
#include <string>
using std::cout;

template <typename T>
std::ostream & cprint(T &t,  std::string msg = "Container", std::ostream & stream = cout){
    stream << msg << "\t{ ";
    for(typename T::iterator it = t.begin(); it != t.end(); it++)
        stream << *it << " ";
    stream << "}\n";

    return stream;
}

我在一个单独的文件中有一个模板函数。我正在尝试在 ma​​in.cpp 文件中转发声明它。

extern template std::ostream & cprint<std::vector<int>>
(T &t,  std::string msg = "Container", std::ostream & stream = cout);

我已经尝试了上述方法,但它对我不起作用。

编辑: 假设 other.cpp 具有如下基本功能,

template <typename T>
void func(T x){
    cout << x << endl;
}

如何在 main.cpp 中实例化这个函数?

【问题讨论】:

  • 你遇到了什么错误?
  • 你不仅做错了,而且整个想法都错了,阅读这里stackoverflow.com/questions/495021/…
  • @Slava 好吧,如果您手动指定模板必须适用的所有类型,则可以将模板放入单独的文件中。
  • @HolyBlackCat 'cprint' is not a template functionexpected ';' before '&lt;' token 我得到的错误。
  • @HolyBlackCat 确实如此,但是从 OP 的问题中了解理解程度,这不是他想要做的。我敢打赌下一个 OP 的问题 - 为什么它不起作用。

标签: c++ templates forward-declaration


【解决方案1】:

请记住,您要问的是(通常)不是使用模板的正确方法。

您应该做的是在标头中声明您的模板,并去掉 extern 声明和显式特化。

将模板放入.cpps 通常不是很方便,因为它们要求您指定您希望它们在同一个.cpp 中工作的所有类型。

但是,另一方面,它提高了编译速度,并且生成的二进制文件较小的可能性很小。


如何修复您的代码:

我对您的代码进行了一些更改以使其正常工作。

我还做了一些小的改进。如果您发现它们令人困惑,请在 cmets 中询问。

// 1.cpp
#include <iostream>
#include <string>
#include <vector>

template <typename T>
std::ostream &cprint(const T &t, std::string msg = "Container", std::ostream &stream = std::cout)
{
    stream << msg << " { ";
    for(typename T::const_iterator it = t.cbegin(); it != t.cend(); it++)
        stream << *it << " ";
    stream << "}\n";
    return stream;
}

template std::ostream &cprint(const std::vector<int> &, std::string, std::ostream &);

// 2.cpp
#include <string>
#include <iostream>
#include <vector>

template <typename T> std::ostream &cprint(const T &, std::string = "Container", std::ostream & = std::cout);

int main()
{
    std::vector<int> v{1,2,3};
    cprint(v);
}

重要部分如下:

  • 显式实例化。它必须与模板定义位于同一文件中。
    template std::ostream &amp;cprint(const std::vector&lt;int&gt; &amp;, std::string, std::ostream &amp;);

  • 声明。它必须在您要使用模板的文件中。 template &lt;typename T&gt; std::ostream &amp;cprint(const T &amp;, std::string = "Container", std::ostream &amp; = std::cout);

请注意,如果编译器无法推断出模板参数,您可以在显式实例化和外部声明中手动指定模板参数。


用一个被编辑成问题的虚拟模板做同样的事情留给读者作为练习。

【讨论】:

  • 你是对的。我完全以错误的方式做这件事。我应该使用标题并在标题中定义所有内容。
  • 答案解决了问题,但我不同意模板定义只属于头文件,或者它们的主要目的是减少编译时间或二进制大小;事实上,它们可以做相反的事情,特别是如果它们是在标题中定义的。
  • @gcbenison 点了,编辑了答案。我同意,有时将模板放入 .cpp 可能会很有用。关于更好的编译速度和较小的二进制大小的部分是关于位于.cpps,not 标头中的模板。我更改了措辞以使其更清楚。
【解决方案2】:

除了this,你还应该阅读:using extern template (C++11)

要使用 extern 延迟实例化,您必须完全匹配函数签名,因此除非将 T 定义为 std::vector&lt;int&gt; 或其别名 - 与您的模板声明匹配,否则下面将无法工作。:

extern template std::ostream & cprint<std::vector<int>>
(T &t,  std::string msg = "Container", std::ostream & stream = cout);

修复,

extern template std::ostream& cprint<std::vector<int>>
(std::vector<int>&, std::string msg = "Container", std::ostream & stream = cout);

Here

更具体地说,

Header.hpp 文件中,我有它的声明和延期:

template <typename T>
std::ostream & cprint(T &t,  std::string msg = "Container", std::ostream & stream = cout){
    stream << msg << "\t{ ";
    for(typename T::iterator it = t.begin(); it != t.end(); it++)
        stream << *it << " ";
    stream << "}\n";

    return stream;
}

//defer instantiation
extern template std::ostream& cprint<std::vector<int>>
(std::vector<int>&, std::string msg = "Container", std::ostream & stream = cout);

现在,ma​​in.cpp 文件中,我有:

int main(){
    std::vector<int> v{1, 2, 3, 4, 5};
    cprint(v);
}

Header.cpp 文件中,我有它的实例化:

template std::ostream& cprint<std::vector<int>>
(std::vector<int>&, std::string msg = "Container", std::ostream & stream = cout);

如所见Here

======================

编辑:关于您最近的编辑:

编辑:假设 other.cpp 具有如下基本功能,

template <typename T>
void func(T x){
    cout << x << endl;
}

如何在 main.cpp 中实例化这个函数?

如果翻译单元,main.cpp 看到 函数模板的声明 func(要么来自包含的标题,要么你 (re-(forward- )) 在 main.cpp 中声明它,它将编译为调用 function template-specialization1,但链接器将无法找到function template-specialization 除非它看到该 function template-specialization 的定义是在(另一个)翻译单元中实例化的。


注意:“函数模板特化”是从函数模板实例化的函数。见temp.fct/1

【讨论】:

  • 你确定你回答了 OP 的问题吗?
  • @WhiZTiM 我已经编辑了问题以简化解决方案。即使我明确编写所有类型的编译器仍然会出错。
  • @WhiZTiM 'cprint' is not a template function 根据您的代码出错
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多