6

There are a lot of online documents explaining how to write template methods, but not much example about how to call them, how to use them in code.

I have a template method like this:

VectorConvertor.h

template <class T>
static void AppendToVector(std::vector<T> & VectorToBeAppended,
                           std::vector<T> & VectorToAppend);


VectorConvertor.cpp

template <class T>
void VectorConvertor::AppendToVector(std::vector<T> & VectorToBeAppended,
                                     std::vector<T> & VectorToAppend)
{
    for (std::vector::size_type i=0; i<VectorToAppend.size(); i++)
    {
        VectorToBeAppended.push_back(VectorToAppend.at(i));
    }
}

Usage attempt in code:

std::vector<uint8_t> InputData, OutputData;
// ...
VectorConvertor::AppendToVector(OutputData, InputData);


I compile this code without any error. But when I try to use this method I get the following errors:

error LNK1120: 1 unresolved externals

and

error LNK2019: unresolved external symbol "public: static void __cdecl VectorConvertor::AppendToVector(class std::vector > &,class std::vector > &)" (??$AppendToVector@E@VectorConvertor@@SAXAEAV?$vector@EV?$allocator@E@std@@@std@@0@Z) referenced in function "public: staticclass std::vector > __cdecl Utf8::WStringToUtf8(class std::basic_string,class std::allocator >)" (?WStringToUtf8@Utf8@@SA?AV?$vector@EV?$allocator@E@std@@@std@@V?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@3@@Z)


When I don't use this method in my code I don't get any error messages. What am I doing wrong while calling it? Am I missing something?


I'm using Visual Studio 2010 Express Edition.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
hkBattousai
  • 10,583
  • 18
  • 76
  • 124
  • 1
    Not helpful, but these kinds of error messages were just the reason why i stopped coding with C++. – Jan Thomä Nov 24 '10 at 19:30
  • For clarity, do not confuse `template method` (which is a design pattern) with `class template member function` and `function template`. – Steve Townsend Nov 24 '10 at 19:39

5 Answers5

7

In C++ you can't separate the definition in a .cpp file when using templates. You need to put the definition in the header file. See:

http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12

Nathan S.
  • 5,244
  • 3
  • 45
  • 55
  • The language does allow you to split a template definition from its implementation, with the `export` keyword. It's your compiler that is likely to forbid it. – wilhelmtell Nov 24 '10 at 19:46
  • @wilhelmtell: Unfortunately, this will be deprecated in C++1x, which makes it _very_ unlikely that any other compiler will bother to implemented it. `:(` (Shouldn't you be herding you jython cache?) – sbi Nov 24 '10 at 19:48
  • @sbi: it's actually not deprecated in C++0x, it's removed (the keyword is still a keyword, but is just reserved, it has no meaning). Ding dong, the witch is dead, etc. – Steve Jessop Nov 24 '10 at 20:07
  • @sbi why unfortunately? compiler vendors deserve to be called "compatible" for their hard work. if no one (-ish) implements `export` then maybe it's not a good idea and it should be shot, hanged and bullied in to bed. – wilhelmtell Nov 24 '10 at 20:28
  • @Steve: Bugger. And it had been such a nice day up to now. – sbi Nov 24 '10 at 21:21
  • 1
    @sbi: As I understand it, it was EDG who pushed most strongly for its removal. Everyone else was happy to continue being non-conforming. It can only be implemented by, in effect, copying the whole C++ compiler into the linker (you can leave out the tokenizer). So they always argued that it was a bad feature, they just implemented it anyway because they're hardcore. Probably C++ should have a better build model, probably it's never going to get one, but I think export isn't it. – Steve Jessop Nov 24 '10 at 22:12
  • @Steve: Yep, it had been EDG. – sbi Nov 25 '10 at 06:05
  • @wilhelmtell: I wish you hadn't deleted your response to another thread in which you disagree with the was C++ is taught in colleges. I completely agree with you. – John Dibling Nov 25 '10 at 19:44
5

You need to put the body of the function in the header file. See this FAQ.

Matt K
  • 13,370
  • 2
  • 32
  • 51
2

Template linking can get tricky. But the simplest solution is usually:

Put all template definitions in header files.

In this case, you should move the contents of VectorConverter.cpp to VectorConverter.h (or possibly #include "VectorConverter.cpp" at the bottom of VectorConverter.h).

aschepler
  • 70,891
  • 9
  • 107
  • 161
0

Besides placing the definition of the template function in the header, or including the source file (cpp file), you could explicitly instantiate your function for whichever types you need it.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
0

The errors are because of trying to write the definition of the template method in the CPP file. In order to reduce the linking time, it is a rule to write the implementation (definition) of the inline and template methods in the header file. The code below is the correct way of declaring and defining a template method.

VectorConvertor.h

class VectorConvertor
{
    public:
        template <class T>
        static void AppendToVector1(        std::vector<T> & VectorToBeAppended,
                                    const   std::vector<T> & VectorToAppend);

        template <class T>
        static void AppendToVector2(        std::vector<T> & VectorToBeAppended,
                                    const   std::vector<T> & VectorToAppend);

        template <class T>
        static void AppendToVector3(        std::vector<T> & VectorToBeAppended,
                                    const   std::vector<T> & VectorToAppend);


}

template <class T>
void VectorConvertor::AppendToVector1(          std::vector<T> & VectorToBeAppended,
                                        const   std::vector<T> & VectorToAppend)
{
    VectorToBeAppended.reserve(VectorToBeAppended.size() + VectorToAppend.size());
    for (std::vector<T>::size_type i=0; i<VectorToAppend.size(); i++)
    {
        VectorToBeAppended.push_back(VectorToAppend[i]);
    }
}

template <class T>
void VectorConvertor::AppendToVector2(          std::vector<T> & VectorToBeAppended,
                                        const   std::vector<T> & VectorToAppend)
{
    VectorToBeAppended.reserve(VectorToBeAppended.size() + VectorToAppend.size());
    for (std::vector<T>::const_iterator cit=VectorToAppend.cbegin(); cit!=VectorToAppend.cend(); ++cit)
    {
        VectorToBeAppended.push_back(*cit);
    }
}

template <class T>
void VectorConvertor::AppendToVector3(          std::vector<T> & VectorToBeAppended,
                                        const   std::vector<T> & VectorToAppend)
{
    VectorToBeAppended.insert(VectorToBeAppended.end(), VectorToAppend.cbegin(), VectorToAppend.cend());
}

VectorConvertor.cpp

// Nothing to write in the CPP file.

And, this is how to use it in the code:

std::vector<uint8_t> InputData, OutputData;
// ...
VectorConvertor::AppendToVector3(OutputData, InputData);
hkBattousai
  • 10,583
  • 18
  • 76
  • 124