RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 775615
Accepted
Naf
Naf
Asked:2020-01-25 23:10:48 +0000 UTC2020-01-25 23:10:48 +0000 UTC 2020-01-25 23:10:48 +0000 UTC

使用结构的函数模板

  • 772

我有结构来定义一个点:

struct point_d
{
    double x;
    double y;
};

和

struct point_f
{
    float x;
    float y;
};

并且有一个将点数组写入文件的方法,该方法是静态的并且在 export_to_file 类中。

h文件中的方法描述:

template<typename T>
static void save_to_bln_contour(deque<T> points, const int type_contour, const string filename);

cpp文件中的方法:

template<typename T>
export_to_file::save_to_bln_contour(deque<T> points, const int type_contour, const string filename)
{
/**/
}

我这样调用方法:

export_to_file::save_to_bln_contour<point_d>(points, 1, "test1");

如果此方法包含在我调用它的同一类中,则没有错误。怎么了?

如果我按上述方式编写,那么工作室链接器会发誓错误代码 LNK2019:

"public: static void __cdecl export_to_file::save_to_bln_contour(class std::deque >,int,class std::basic_string,class std::allocator >)" (?? $save_to_bln_contour@Upoint_d@@@export_to_file@@SAXV?$ deque@Upoint_d@@V?$allocator@Upoint_d@@@std@@@std@@HV?$basic_string@DU?$char_traits@D@std@@V ?$allocator@D@2@@2@@Z ) 和 "public: void __cdecl surface_fault::get_points_intersect(class surface_res &,class fault *)" (?get_points_intersect@surface_fault@@QEAAXAEAVsurface_res@@PEAVfault@@@Z) GRD_MBA E:\Projects\GRD_MBA\GRD_MBA\surface_fault.obj 1

工作室中的编码存在问题。

我需要为 point_d 结构和 point_f 结构的点调用save_to_bln_contour方法。

c++
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    Croessmah stands with Russia
    2020-01-26T14:16:53Z2020-01-26T14:16:53Z

    将模板实现移动到头文件,或在“.cpp 文件”中使用给定的一组参数实例化模板。

    下面的情况说明。它是用的gcc,不是cl,但意思是一样的。本质很简单——不同的翻译单元彼此不了解。编译器生成代码并将其提供给链接器,然后链接器决定从哪里获取哪些定义。让我们采用一个非模板函数(为简单起见):

    //func.h
    #ifndef MY_PROJECT_FUNC_H
    #define MY_PROJECT_FUNC_H
    
    void foo();//Объявляем foo
    
    #endif //MY_PROJECT_FUNC_H
    
    
    //func.cpp
    #include "func.h"
    #include <iostream>
    void foo()
    {
       std::cout << "foo" << std::endl;
    }
    
    //main.cpp
    #include "func.h"
    
    int main()
    {
       foo();//используем функцию
    }
    

    让我们编译main.cpp: g++ main.cpp -c -o main.o

    收到一个文件main.o。如您所见,没有错误(-c 开关只是“告诉”编译器您只需要编译成一个对象,无需调用链接器)。
    在这种情况下,编译器只需要声明即可汇编。

    让我们编译第二个文件:g++ func.cpp -c -o func.o

    这里一切都很好。现在让我们把它们放在一起。我们也将使用它g++,他自己知道如何调用链接器(以免糊弄他的脑袋ld)。

    g++ -o main main.o func.o

    一切都聚集了。我们开始:./main一切都很好,一切正常。
    现在让main.cpp我们像这样改变它:

    //main.cpp
    #include "func.h"
    
    int main()
    {
        foo();
        foo();
    }
    

    让我们编译main.cpp:g++ -c -o main.o main.cpp

    让我们把它变成一个二进制文件:g++ -o main main.o func.o

    一切都很好。但是我们没有func.cpp再次编译。我们只是编译main.cpp然后与现有的func.o. 也就是说,我们没有花费 100,500 小时来构建其他库,因为我们更改了main.cpp. 我们只编译更改的部分就足够了。

    现在大约undefined reference。让我们取相同的文件并尝试以这种方式编译:

    g++ -o main main.cpp

    收到undefined reference。为什么?问题是编译时,编译器main.cpp有一个声明foo,它足以检查这个名字的正确使用foo。链接器将查找此 foo 所在的位置。但是链接器也不知道在哪里foo寻找它,因为我们没有将他指向func.o. 因此,它告诉我们发生了这样那样的错误。如果我们告诉他 func.o,那么一切都会好起来的:

    g++ -o main main.cpp func.o

    同时,请注意,func.cpp一般来说,它在我们的任何地方都不再被照亮。Bfunc.o有我们需要的函数定义foo,所以链接器可以找到它。

    现在到模板。

    首先考虑我们没有的情况func.cpp:

    //func.h
    #ifndef MY_PROJECT_FUNC_H
    #define MY_PROJECT_FUNC_H
    
    template<typename T>
    void foo()
    {
    }
    
    #endif //MY_PROJECT_FUNC_H
    
    //main.cpp
    #include "func.h"
    
    int main()
    {
        foo<int>();
        foo<double>();
    }
    

    收集:g++ -o main main.cpp
    一切都很好。

    在这种情况下,foo 不是一个函数,它是一个函数模板。
    根据这种模式,编译器可以构建代码。
    使用时foo:foo<int>();编译器根据给定的模板(实例化)生成函数代码,其中T是 type int。对于foo<double>();- 同样,只有T- double。现在让我们func.cpp在那里添加和移动实现foo:

    //func.h
    #ifndef MY_PROJECT_FUNC_H
    #define MY_PROJECT_FUNC_H
    
    template<typename T>
    void foo();
    
    #endif //MY_PROJECT_FUNC_H
    
    //func.cpp
    #include "func.h"
    
    template<typename T>
    void foo()
    {
    }
    

    收集:g++ -o main main.cpp
    并得到undefined reference。

    为什么?因为我们有声明foo,但没有定义,所以编译器无法实例化函数(根据模板生成),编译器只匹配了使用--一切正常,把对象交给链接器,链接器找不到执行,因为他不知道它在哪里搜索。好的,让我们这样做:

    g++ -o main main.cpp func.cpp
    又一次undefined reference。

    毕竟,为什么我们指出了实现的位置?现在,这就是单独编译再次发挥作用的地方。 main.cpp也编译func.cpp了。他们对彼此一无所知。在main.cpp使用foo中,但func.cpp实际上没有这个模板的实例。为什么不存在?它func.cpp没有在任何地方使用,因此编译器没有实例化模板。也就是说,如果不使用具有特定模板参数集的模板,则编译器将不会为具有给定模板参数集的模板生成代码。怎样成为?让我们“强制”编译器func.cpp生成代码。如何?就在我们使用的某个地方foo<тип>,例如:

    //func.cpp
    #include "func.h"
    
    
    template<typename T>
    void foo()
    {
    }
    
    
    void bar()
    {
        foo<int>();
        foo<double>();
    }
    

    我们收集:g++ -o main main.cpp func.cpp

    一切都已组装并正常工作。为什么?func.cpp出现bar了一个使用foo<int>and的函数foo<double>,并且在这个翻译单元中有一个模板定义,这意味着编译器将实例化模板,现在func.cpp里面有必要的定义,链接器可以找到它们。那些。任务完成 - 我们已经强制编译器实例化模板。但是为此我们不得不使用另一个非模板函数。但是有一个更合适的解决方案——显式实例化。显式实例化导致编译器使用给定的参数集实例化模板。让我们改变func.cpp

    //func.cpp
    #include "func.h"
    
    
    template<typename T>
    void foo()
    {
    }
    
    
    template void foo<int>();//Явное инстанцирование шаблона foo с параметром int
    template void foo<double>();
    

    我们收集:g++ -o main main.cpp func.cpp

    一切都很好,一切都组装好了。但是,值得添加到 main 中,例如foo<char>();,我们将如何再次获得undefined reference,因为我们的编译器没有为这组参数 ( char) 生成代码。也就是说,我们可以将模板的实现移动到.cpp,但在这种情况下,我们需要以某种方式实例化模板以获得必要的参数集。

    我的帖子原文:http ://www.cyberforum.ru/cpp-beginners/thread1798717.html#post9488987

    • 2

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5