对类模板成员函数的未定义引用

发布于 2025-01-07 10:39:02 字数 909 浏览 1 评论 0原文

我想在模板类方法中使用迭代器。 这是我的代码:(testclass.h)

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first );
};

和文件 testclass.cpp:

template<typename T, typename container>
void TestClassX<T, container>::gen(typename container::iterator first)
{

}

当我尝试运行它时:

TestClassX<unsigned, std::vector<unsigned> > testx;
testx.gen(it);

我收到错误:

Error:undefined reference to `TestClassX<unsigned int, std::vector<unsigned int, std::allocator<unsigned int> > >::gen(__gnu_cxx::__normal_iterator<unsigned int*, std::vector<unsigned int, std::allocator<unsigned int> > >)'

我使用 mingw32 4.4

我想要一个可以写入不同容器(如 std::vector)的类, std::list、QVector 或 QList 都具有 STL 风格的迭代器。

I want to use iterators in template class method.
Here is my code: (testclass.h)

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first );
};

and file testclass.cpp:

template<typename T, typename container>
void TestClassX<T, container>::gen(typename container::iterator first)
{

}

When i try to run it:

TestClassX<unsigned, std::vector<unsigned> > testx;
testx.gen(it);

I get an error:

Error:undefined reference to `TestClassX<unsigned int, std::vector<unsigned int, std::allocator<unsigned int> > >::gen(__gnu_cxx::__normal_iterator<unsigned int*, std::vector<unsigned int, std::allocator<unsigned int> > >)'

I use mingw32 4.4

I want to have a class that can write to different containers like std::vector, std::list, QVector or QList all that have STL-style iterators.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

拥有 2025-01-14 10:39:02

模板类方法必须在头文件中定义。当您使用模板类时,编译器实际上会为给定的模板参数编译该类的版本。因此,要求每个方法的主体在包含头文件时都可用。

删除源文件并将主体包含在 testclass.h 中:

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first ) {

    }
};

Template class methods must be defined in the header file. When you use a template class, the compiler actually compiles a version of that class for the given template parameters. Therefore, it is a requirement that the body of each method is available when including the header file.

Remove you source file and include the body in testclass.h:

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first ) {

    }
};
惟欲睡 2025-01-14 10:39:02

模板类方法不需要在头文件中定义。但如果这样做,您需要定义一个单独的编译单元(例如 templates.cpp),并包含模板类的源代码文件(例如 #include "container.cpp" // the .cpp NOT the .hpp 文件)
那么您需要定义您正在使用的模板的实例(例如模板类Container;)。
您还需要为模板类定义对象(例如Link)。在这种特殊情况下,由于我们使用指向该对象的指针(例如 Container 中的 Link*),我们只需要“转发声明”该对象。

这是完整的 template.cpp 文件。您将对其进行编译并与其余代码链接。

class Link;
#include "Container.cpp"    // use the source code, not the header
template class Container<Link*>; 

我喜欢使用这种方法,因为它可以防止编译器自动生成模板类实例,并在找不到它时让您知道。

使用选项 -fno-implicit-templates 通过 gcc 进行编译。

当您构建时,所有内容都将正常编译,但收集器将为使用该模板的所有对象重新编译 templates.cpp 文件。

Template class methods NEED NOT be defined in the header files. But if you do this you need to define a separate compilation unit (for example templates.cpp) and in that you include the source code file of the template class (eg. #include "container.cpp" // the .cpp NOT the .hpp file)
then you need to define the instances of the templates that you are using (eg. template class Container;).
You also need to define the object for the template class (eg Link). In this particular case, since we are using a pointer to this object (eg Link*, in Containter ) we merely need to 'forward declare' that object.

Here is the full template.cpp file. Which you would compile and link in with the rest of the code.

class Link;
#include "Container.cpp"    // use the source code, not the header
template class Container<Link*>; 

I like using this method because it prevents the compiler from generating template class instances automagically and lets you know when it can't find it.

Compile with gcc using the option -fno-implicit-templates.

When you build everything will be compiled as normal but then the collector will recompile the templates.cpp file for all the objects that use the template.

咆哮 2025-01-14 10:39:02

如前所述,实例化模板时,定义必须存在于同一编译单元中。

我个人更喜欢将定义与声明分开。
这可以保持头文件更清晰,并在视觉上将接口与实现分开。

因此,一种解决方案如下:

//TestClass.hpp

//Interface:
template<typename T>
class TestClassX
{
public:
    void gen(int a);
    //more declaraions...
}; 

//Implementations:
template<typename T>
void TestClassX<T>::gen(int a)
{
    //beautiful code
}

您可以将实现和接口放在单独的文件中
(分别是 TestClass.hppITestClass.hpp)。
TestClass.hpp 最初将#include ITestClass.hpp,然后定义函数,如上例所示。
然后,客户端只需要#include TestClass.hpp

As previously stated, the definition must exist in the same compilation unit when the template is instantiated.

I personally prefer to keep the definitions separated from the declarations.
This keeps the header files cleaner and visually separates the interface from the implementation.

One solution can therefore be as follows:

//TestClass.hpp

//Interface:
template<typename T>
class TestClassX
{
public:
    void gen(int a);
    //more declaraions...
}; 

//Implementations:
template<typename T>
void TestClassX<T>::gen(int a)
{
    //beautiful code
}

You could place the implementation and the interface in separate files
(i.e TestClass.hpp and ITestClass.hpp respectively).
TestClass.hpp will initially #include ITestClass.hpp and then define the function as shown in the example above.
The clients will then only need to #include TestClass.hpp.

缪败 2025-01-14 10:39:02

可能值得在这里查看这个答案,看看 inline 是否适合您。
https://stackoverflow.com/a/51585746/1440598

May be worth looking at this answer over here to see if inline is appropriate for you.
https://stackoverflow.com/a/51585746/1440598

一杯敬自由 2025-01-14 10:39:02

从技术上讲,这样做是可行的,您只需要向链接器解释在哪里可以找到实现,但在现实世界的经验中,很少这样做,因为它需要分配样板并且不允许您使用 constexpr code> 变量来自 .hpp.cpp 中的另一个文件,因为编译器会抱怨重新定义的使用。

我个人解决这个问题的一种方法是在另一个头文件中使用辅助函数并从基本头文件中调用它。例如,假设我们在 encoder.hpp 中有一个类 Encoder,那么我们可以创建另一个名为 encoder_impl.hpp 的文件并执行以下操作。

encoder_impl.hpp

#include ... // include what you need. 
enum class ENCODE_TYPE : u8 { ... };
enum class CONN_TYPE : u8 { ... };

namespace encoder_impl {

 template<ENCODE_TYPE E, CONN_TYPE C>
 static inline void helper(...){...};

 template<> void helper<ENCODE_TYPE::LOGON, CONN_TYPE::QUOTE>
 (...){...}; 

} // encoder_impl

encoder.hpp

#include ... // include what you need. 
#include "encoder_impl.hpp"

namespace encoder {

template <CONN_TYPE C>
struct Encoder{

  template<ENCODE_TYPE E>
  inline void encode(...){
    encoder_impl::helper<E, C>(...);
  }

  inline buffer_conn<C>& get_buff() const { return buff; };

private:
  buffer_conn<C> buff; //just an example needing CONN_TYPE

} // encoder

这确实有一个缺点,即您的“实现”文件也会重新包含正常 .hpp 文件时的所有内容使用,但这并不真正影响运行时性能,仅影响编译时间。

Its technically possible to do this, you just need to explain to the linker where the implementation can be found, but in real world experience, this is seldom done as its requires allot of boiler plate and disallows you to use constexpr variables from another file in both the .hpp and .cpp as the compiler will complain about redefinition use.

One way i personally solve this is by using a helper function in another header file and call it from the base header file. For example lets say we have a class Encoder in encoder.hpp than we can create another file called encoder_impl.hpp and do the following.

encoder_impl.hpp

#include ... // include what you need. 
enum class ENCODE_TYPE : u8 { ... };
enum class CONN_TYPE : u8 { ... };

namespace encoder_impl {

 template<ENCODE_TYPE E, CONN_TYPE C>
 static inline void helper(...){...};

 template<> void helper<ENCODE_TYPE::LOGON, CONN_TYPE::QUOTE>
 (...){...}; 

} // encoder_impl

encoder.hpp

#include ... // include what you need. 
#include "encoder_impl.hpp"

namespace encoder {

template <CONN_TYPE C>
struct Encoder{

  template<ENCODE_TYPE E>
  inline void encode(...){
    encoder_impl::helper<E, C>(...);
  }

  inline buffer_conn<C>& get_buff() const { return buff; };

private:
  buffer_conn<C> buff; //just an example needing CONN_TYPE

} // encoder

This does have the downside that your 'implementation' file will also re-include everything when the normal .hpp file is used, but this does not really affect run-time performance only compile time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文