0

I'm trying to make a quick utility class that extends std::vector through composition. For this, I want to make it as generic as possible.

The class works well when declared and implemented in a single file (i.e. main.cpp):

main.cpp

#include <iostream>
#include <algorithm>
#include <vector>

template<typename T>
class FVector {

public:

    FVector(std::vector<T> vector): _vector(vector) {}

    template <typename unaryOperation>
    void forEach(unaryOperation op) {
        std::for_each(_vector.begin(),_vector.end(),op);
    };

private:

    std::vector<T> _vector;

};

int main(int argc, const char * argv[]) {

    auto printInt = [](int i){ std::cout << i << std::endl; };
    std::vector<int> numbers{1, 2, 3, 4, 5};
    FVector<int> fNumbers{numbers};
    fNumbers.forEach(printInt);

    return 0;

}

But when I try to put the class in its own .h and .cpp file, the compiler won't find the Constructor nor the function.

FVector.h

...
#include <vector>

template<typename T>
class FVector {

public:

    FVector( std::vector<T> );

    template <typename unaryOperation>
    void forEach(unaryOperation);

private:

    std::vector<T> _vector;


};
...

FVector.cpp

#include "FVector.hpp"
#include <algorithm>

template <typename T>
FVector<T>::FVector( std::vector<T> vector ): _vector(vector) {}

template <typename T>
template <typename unaryOperation>
void FVector<T>::forEach(unaryOperation op) {
    std::for_each(_vector.begin(),_vector.end(),op);
}

main.cpp

#include <iostream>
#include "FVector.hpp"

int main(int argc, const char * argv[]) {

    auto printInt = [](int i){ std::cout << i << std::endl; };
    std::vector<int> numbers{1, 2, 3, 4, 5};
    FVector<int> fNumbers{numbers};
    fNumbers.forEach(printInt);

    return 0;

}

error

Function 'FVector::forEach<(lambda at blah/main.cpp:95:21)>' has internal linkage but is not defined

Clearly something in my syntax is very wrong, but I can't find how to declare/implement the functions.

Thanks!

whtlnv
  • 2,109
  • 1
  • 25
  • 26
  • You need to define your `forEach` in the header file. See also: http://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file – Vittorio Romeo Mar 21 '17 at 09:29
  • @VittorioRomeo So there's no way to separate the declaration and implementation? – whtlnv Mar 21 '17 at 09:32
  • yes, you can have an extra "inline" header file and include it. This is a very commonly discussed topic, please search for it – Vittorio Romeo Mar 21 '17 at 09:33

2 Answers2

1

Right now, there is only a recipe how to create an instance for FVector, but none is created. You need to instantiate one. The source file has no way to "know" which instances are needed since it is not included somewhere where a class from the template is used, that is the problem (well, incorrectly formulated, but I hope you get the point - basically, when a file includes a header, it can use everything in the header to create a class out of a template, but not what is in some source it does not even know)

This can be done by writing something like

template class FVector<double>;

at the end of your source file to specialize it over double, and then the same for every forEach-specialization that should exist. I usually have another file, ClassNameSpecialization.h (that is FVectorSpecialization.h in your case), which contains only such lines and is included at the end of the source file. Makes it easy to add some specializations.

If you want FVector to be dynamic, being able to work with any template parameter given that could possibly work with the code, you need to implement it in the header, although this is ugly of course.

Aziuth
  • 3,652
  • 3
  • 18
  • 36
1

C++ templates are special animals: each instanciation of the template is a different class. That means that if you try to put the template class definition in its own cpp, as no instanciation will be required in that translation unit, the compiler will generate none. And when you will try to use one from another translation unit, the linker will complain because it cannot find the concrete definition.

The standard declares in draft n4296 (emphasize mine):

14 Templates [temp]
...
A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated (14.7.1) unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required.

That's why the common use is to write the full definition on a template in the header file, to make sure that the definition will be present in every translation unit.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252