提问人:justHelloWorld 提问时间:5/2/2016 最后编辑:CommunityjustHelloWorld 更新时间:12/1/2018 访问量:2537
功能。。。已经定义了主体和功能模板
function ... has already a body & function template has already been defined
问:
我有这个头文件:
实用程序.h:
#pragma once
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <Windows.h>
using namespace std;
template<std::size_t> struct int_ {};
template <class Tuple, size_t Pos>
std::ostream& print_tuple(std::ostream& out, const Tuple& t, int_<Pos>);
struct Timer {
public:
Timer();
void start();
double getMilliSec();
private:
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2; // ticks
};
//...
#include "Utility.cpp"
而这个实现文件:
实用程序.cpp:
#include "Utility.h"
template <class Tuple, size_t Pos>
std::ostream& print_tuple(std::ostream& out, const Tuple& t, int_<Pos>) {
...
}
Timer::Timer() {
// get ticks per second
QueryPerformanceFrequency(&frequency);
}
void Timer::start() {
QueryPerformanceCounter(&t1);
}
double Timer::getMilliSec() {
QueryPerformanceCounter(&t2);
return (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
}
这将返回以下错误:
error C2995: 'std::ostream &print_tuple(std::ostream &,const Tuple &,int_<Pos>)': function template has already been defined
error C2084: function 'Timer::Timer(void)' already has a body
...
问题不在于守卫(如本问题中所建议的),因为我使用#pragma once
我已经阅读了为模板类实现实现 .tpp 文件的信息,但我发现这是一个可怕的解决方案,因为 Visual Studio 不会从此文件中格式化任何内容。
尝试定义 Utility.tpp:(错误的解决方案)
所以我用 in 代替并定义......#include "Utility.cpp
#include "Utility.tpp
Utility.h
实用程序.tpp
Timer::Timer() {
// get ticks per second
QueryPerformanceFrequency(&frequency);
}
void Timer::start() {
QueryPerformanceCounter(&t1);
}
double Timer::getMilliSec() {
QueryPerformanceCounter(&t2);
return (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
}
现在返回的错误是:
1>Memoization.obj : error LNK2005: "public: __cdecl Timer::Timer(void)" (??0Timer@@QEAA@XZ) already defined in HelloWorld.obj
...
顺便说一句,这是主要的:
HelloWorld.cpp:
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//#include "Memoization.cpp"
#include<vector>
#include"Utility.h"
using namespace std;
int main()
{
}
尝试定义 Utility.tpp:(正确的解决方案,最后)
正如评论中让我注意到的那样,作为一个白痴,我导入了文件中的方法,显然我应该导入模板函数,所以在包含的同时包含 3 个函数。Time
.tpp
Utility.tpp
print_tuple
Utility.cpp
Timer
答:
从 Utility.h 中删除 #include“Utility.cpp”行。 然后再次编译实用程序 .cpp
评论
如果要将 cpp 文件包含在头文件中,则需要将该 cpp 文件排除在项目中的编译之外。如果没有,则头文件将具有 cpp 文件所具有的内容,当编译器将 cpp 文件编译为对象时,您将拥有定义的两个副本。一个在头文件中,因为它中有 cpp 文件的副本,另一个在 cpp 文件中,因为这是实际编译的内容。这会导致重新定义错误。
从编译中删除 Utility.cpp 后,任何其他包含 Utility.h 的 cpp 文件都将具有完整源代码的副本,因为 Utility.cpp 也包括在内。
若要从编译中删除实用工具 .cpp,请参阅:如何从 Visual Studio 编译中排除文件?
如果使用 cpp 文件的唯一原因是 tpp 文件不将 C++ 代码格式化为 C++,则可以将 MSVS 配置为将 tpp 文件视为 C++ 文件。如果转到“工具”->“选项”-“>”文本编辑器“-”文件扩展名“>,则可以在格式中添加文件扩展名。在扩展框中输入扩展,从编辑器下拉列表中选择“Microsoft Visual C++”,然后单击“添加”。
现在,您可以使用 tpp 文件而不是 cpp 文件,并且不必记住从构建中排除 cpp 文件。您还可以遵守现代惯例。
主要有两个问题:
您已将预期的头代码放在“.cpp”文件中,默认情况下,IDE 会将其视为主源代码文件(转换单元)。
您将非函数定义(类成员函数)包含在标头的全局命名空间中。当该标头包含在两个或多个翻译单元中时,您将收到一个定义规则 (ODR) 冲突。在实践中,链接者会抱怨。
inline
要解决此问题,请执行以下操作:
将文件扩展名从“.cpp”更改为例如“.hpp”或只是普通的“.h”。它是用于头文件的代码。文件扩展名应该反映这一点,而不是误导。
声明函数,或将定义放在类定义中。
inline
在其他新闻中,可能来自标准库中的一个时钟将达到您的目的,这样您就不必包含在标题中。它确实拖入了无数不合理的宏。默认情况下,包括小写字母和宏,因此此代码非常不好。<chrono>
<windows.h>
min
max
上一个:为什么模板只能在头文件中实现?
下一个:为什么模板只能在头文件中实现?
评论
#include "Utility.cpp"