1

The problem I am struggling with is the declaration of specialized template function inside template class (I keep class declaration in header file and define member functions in associated .C file).

I have template class representing Points. The header file is presented below:

//...

template<typename T, int dim=3> // T - coords. type, int dim - no. of dimensions
class Point {
    public:
        // ...
        // function below sets val at the given position in array m_c and returns reference
        template<int position> Point& set(T val); 
    private:
        T m_c[dim]; // coordinates
};

//...

definition of function set is placed in .C file:

template<typename T, int dim> template<int position> Point<T, dim>& Point<T, dim>::set(T val){
    // ...
    return *this;
}

As I understand this is the most general form of its definition.

In main function I create Point with float as T and try to set some values in the array:

int main(int argc, char** argv) {
    Point<float> p1;
    p1.set<0>(3).set<1>(3.6).set<2>(3);
    //...
}

In order to make this possible with definition of the member functions of template outside header file I need to inform compiler about specialization in .C file:

template class Point<float>;

and I need as well to declare usage of set function, which I try to accomplish this way (and this piece of code is the problem):

template<> template<int> Point<float>& Point<float>::set(float);

That unfortunately doesn't do the job and I get errors:

/tmp/ccR7haA5.o: In function `main':
.../pdim.C:32: undefined reference to `Point<float, 3>& Point<float, 3>::set<0>(float)'
.../pdim.C:32: undefined reference to `Point<float, 3>& Point<float, 3>::set<1>(float)'
.../pdim.C:32: undefined reference to `Point<float, 3>& Point<float, 3>::set<2>(float)'

I would really appreciate an explanation from someone who may know how to cope with this problem. Thanks.

mbes
  • 56
  • 1
  • 4
  • possible duplicate of [Why can templates only be implemented in the header file?](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – David Brown Oct 22 '13 at 19:05
  • In order to use a specialization of `set` in a TU where you cannot instantiate `set`, you need to "export" the specific specialization required from the TU where it is instantiated (I'll have to look up the syntax). – dyp Oct 22 '13 at 19:11
  • 1
    Unfortunately, proposed topic doesn't relate to my problem. I'm wondering how function like this: `template Point& set(T val);` should be declared - in my understanding how to tell the compiler to generate adequate code. In this example to use with the instance of the class `Point`. There: [link](http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=%2Fcom.ibm.vacpp6m.doc%2Flanguage%2Fref%2Fclrc16explicit_spec_members.htm) are some useful tips, but referred to template member functions with not specified type. – mbes Oct 22 '13 at 19:17
  • Ex. `extern template Point& Point::set<0>(float);` – dyp Oct 22 '13 at 19:17
  • Note: You don't need to explicitly instantiate the class template; the definitions of the member functions do not need to be available to instantiate the class template. – dyp Oct 22 '13 at 19:18
  • I'm sorry, but it doesn't change a thing. – mbes Oct 22 '13 at 19:29
  • Hmm I'll post a complete example (that works for me) as an answer. – dyp Oct 22 '13 at 19:32
  • I would be truly grateful. – mbes Oct 22 '13 at 19:41

1 Answers1

0

In order to provide the definition of a function template specialization in a different TU, you need an explicit instantiation declaration:

[Point.hpp]

template<typename T, int dim=3>
struct Point
{
    template<int position> Point& set(T val);
};

// `extern` makes this an explicit instantiation _declaration_
extern template Point<float,3>& Point<float,3>::set<0>(float);
extern template Point<float,3>& Point<float,3>::set<1>(float);
extern template Point<float,3>& Point<float,3>::set<2>(float);

[Point.cpp]

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

template<typename T, int dim>
template<int position>
Point<T,dim>& Point<T,dim>::set(T val)
{
    // note: non-standard macro
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    return *this;
}

// no `extern`: this is an explicit instantiation _definition_
// which instantiates the function template, and therefore requires the definition
// to be available in this TU
template Point<float,3>& Point<float,3>::set<0>(float);
template Point<float,3>& Point<float,3>::set<1>(float);
template Point<float,3>& Point<float,3>::set<2>(float);

[main.cpp]

#include "Point.hpp"

int main()
{
    // in this TU, there's no definition for the function template
    // hence, it cannot be instantiated
    // however, we can use the explicit instantiations

    Point<float,3>().set<0>(0);
    Point<float,3>().set<1>(0);
    Point<float,3>().set<2>(0);

    // does not compile (linker error):
    //Point<int,3>().set<0>(0);
    //Point<float,4>().set<0>(0);
    //Point<float,3>().set<4>(0);
}
dyp
  • 38,334
  • 13
  • 112
  • 177