3

I want to separate .h and .cpp for template class. Here is the what I was doing:

  1. I wrote directly .h and .cpp like without template. So it creates an exception like Link 2019 Template exception
  2. There are some solution to handle this How to define template class header and implement it in another cpp. I choose solution 3.
  3. According to the solution I added include *.cpp just before #endif inside header.(Still *.cpp includes *.h)(Below code represents this step) It gives

    template has already been defined error.

  4. According to research the way of get rid of this error is(circular dependency) remove #include *.h from *.cpp but this time

    unrecognizable template declaration/definition error

Occured. My question is if I include *.cpp to *.h file. How can we build project as expected? Or this solution is obsolute?

// TestTemp.h
#ifndef _TESTTEMP_H_
#define _TESTTEMP_H_
template<class T>
class TestTemp
{
public:
    TestTemp();
    void SetValue(T obj_i);
    T Getalue();
private:
    T m_Obj;
};
#include "TestTemp.cpp"

#endif

// TestTemp.cpp
#include "TestTemp.h"
template <class T>
TestTemp<T>::TestTemp()
{
}
template <class T>
void TestTemp<T>::SetValue(T obj_i)
{
}

template <class T>
T TestTemp<T>::Getalue()
{
    return m_Obj;
}

#include "TestTemp.h"

int main()
{
    TestTemp<int> a;
    a.Getalue();
    return 0;
}
Community
  • 1
  • 1
Yunus
  • 55
  • 1
  • 10
  • 2
    Did you make sure not to include the cpp file in the build? It should not try to compile it. – NathanOliver Dec 02 '15 at 13:10
  • @NathanOliver I have 3 files which are shown above and I am using Visual Studio in order to build them with these state. – Yunus Dec 02 '15 at 13:13
  • 1
    That’s a terrible article, forgot you every read that. You should not do this. There are other issues with this code (and the article), such as the use of invalid identifiers (cannot use underscore followed by a capital letter at the start of an identifier). – Konrad Rudolph Dec 02 '15 at 13:13
  • 1
    You should read the accepted answer [here](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) and instead of using a cpp file which is going to get compiled by MSVS since it is in the project make it a .tpp file that will not be compiled. – NathanOliver Dec 02 '15 at 13:15
  • @KonradRudolph Another solution is adding template TestTemp t inside *.cpp file. Is this a better solution or anything else? – Yunus Dec 02 '15 at 13:15
  • @NathanOliver I am reading it now thanks – Yunus Dec 02 '15 at 13:16
  • 1
    @Yunus It is definitely a **much** better solution (because it actually works) but it’s restricted to certain situations. In general you simply need to bite the bitter pill and implement the template in a header file, not a `.cpp` file. – Konrad Rudolph Dec 02 '15 at 13:17

1 Answers1

4

Unlike member functions of ordinary classes, member functions of template classes cannot be compiled separately and linked into the executable. The members of a template must be visible to the compiler at the point where they're used. That's what all that nonsensical include stuff in that horrible article is about.

The simplest way to do this is to put the definitions directly into the template definition:

#ifndef TEST_H
#define TEST_H

template <class Ty>
class test {
public:
    void f() { /* whatever */ }
};
#endif

This has the drawback that larger classes become unreadable (cf. Java). So the next step is to move the definitions outside the template, but keep them in the header:

#ifndef TEST_H
#define TEST_H

template <class Ty>
class test {
public:
    void f();
};

template <class Ty>
void test<Ty>::f() { /* whatever */ }

#endif

Many people feel that that's still too cluttered, and want to put the definitions into a separate file. That's okay, too, but you have to make sure that that separate file gets included whenever the original header is used:

#ifndef TEST_H
#define TEST_H

template <class Ty>
class test {
public:
    void f();
};

#include "test.imp"

#endif

This is the file "test.imp":

#ifndef TEST_IMP
#define TEST_IMP

template <class Ty>
void test<Ty>::f() { /* whatever */ }

#endif

Note that "test.imp" is really a header file, so it gets into your code through the #include "test.imp" directive in test.h. It cannot be compiled separately, so should not be named with a .cpp extension, which would, at best, be misleading.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165