1

I have a class called Time. There are only two private members: int hours and int minutes. The public access specifier only contains functions like adding, subtracting etc.

But there's a particular function which doesn't behave the way I want. It's declared public in the class.

This way it compiles:

Time Time::operator*(const int &mult)
{
   minutes = minutes*mult;
   hours = hours*mult + minutes/60;
   minutes %= 60;
   return *this;
}

But what if the argument isn't na int, but a float, or double? I suppose using templates is the best option, rather than overloading the function:

template <class T> Time Time::operator*(const T &mult)
{
   minutes = int(minutes*mult);
   hours = int(hours*mult) + minutes/60;
   minutes %= 60;
   return *this;
}

However, writing it this way gives a compile error:

error LNK2019: unresolved external symbol "public: class Time __thiscall Time::operator*<int>(int const &) " (??$?DH@Time@@QBE?AV0@ABH@Z) referenced in function _main

It means that I can't use operator overloading with templates or what?

Thank you
Robert

lurker
  • 56,987
  • 9
  • 69
  • 103
Robert Lucian Chiriac
  • 686
  • 2
  • 15
  • 24
  • 2
    Where do you write your code? Template member functions need to be in header files (i.e. .h or .hpp), whereas normal member functions are usually defined in implementation files (.cpp or .cxx) – bennofs Jul 04 '13 at 14:20
  • You should put your template code in the header file. – juanchopanza Jul 04 '13 at 14:20
  • The prototypes are written in a header, and the definitions in a implementation file. Like this function. – Robert Lucian Chiriac Jul 04 '13 at 14:21
  • 3
    You can't have templated functions or classes split into header and sources, the caller needs the full definition and if the function is in another source file the full definition is missing. Always put templated classes and functions whole in a header file. – Some programmer dude Jul 04 '13 at 14:21
  • And also why you need to type case to int ?? These data members you can define of Type T or some other type – Sanyam Goel Jul 04 '13 at 14:24
  • @SanyamGoel That's true. I'm making the changes along the path. – Robert Lucian Chiriac Jul 04 '13 at 14:27
  • @JoachimPileborg To be precise, you could, but then you would have to instantiate in the .cpp file all the different version of your class that you might be using later. http://stackoverflow.com/a/4933205/2436175 Advantage: faster compiling. Disadvantage: no inlining, less flexibility, some errors will show at link time instead of at runtime – Antonio Jul 04 '13 at 14:29
  • 1
    Take a look at http://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file – Ilya Kobelevskiy Jul 04 '13 at 14:29
  • On a related note, the arithmetic operators should not mutate any of their operands. – molbdnilo Jul 04 '13 at 14:33

1 Answers1

0

Templates are like patterns for a function. They have to be instantiated before you use them. For your example, you need an instantiation for Time::operator* with T=int, which is obtained by substituting each T in your function with int.

There are two ways this instantiation can happen:

First, there is explicit instantiation, where you have to instantiate the template for all types you want to use it on. An explicit instantiation for your operator* for T=int looks like this:

template Time Time::operator*<int>(const int &mult);

The compiler needs to see the definition to instantiate a template, so here the templated function's implementation must be in the same file or in an included file, but you can put the explicit instantiations together with the implementation of the template in an implementation file.

Another way is implicit instantiation, where the templates get instantiated on the caller side, when they are used. For this method, the template implementation must be visible when you use the template. The easiest way to achieve this is to put the template implementation in the header file where the template is declared.

So you have two choices, either add an explicit instantiation for int to the implementation file or move the template implementation to the header file.

bennofs
  • 11,873
  • 1
  • 38
  • 62
  • Take a look to the comments to the question. – Antonio Jul 04 '13 at 14:33
  • Because the answer is incorrect. You should take a look to the comments and links that have been posted to the question. – Antonio Jul 04 '13 at 14:40
  • When we create a template in a header that contains all the declarations and definitions the Compilation process happens twice in the .cpp file this header is included :P – Sanyam Goel Jul 04 '13 at 14:45
  • In the header: function declaration In the corresponding cpp: function definition, and explicit instantiation (which happens only once). All other cpp files can include that header, and use all the functions/classes explicitly instantiated in the cpp corresponding to the header (my library). The linker will do the rest. – Antonio Jul 04 '13 at 14:54
  • @Antonio With incorrect, do you mean that I didn't say that the instatiation happens only once? – bennofs Jul 04 '13 at 15:22
  • @bennofs If you put the definition of the function in the header file, the instantiation can happen in many places. This is one possibility. The other possibility is to put the definition in a cpp file, and to put all the instantiations that are necessary at the end of that file. This possibility makes your statement "you can't put the implementation in an implementation file" wrong. – Antonio Jul 04 '13 at 22:02
  • @bennofs I am not sure about the terms you used (e.g. implicit instantiation), I would need some time to verify. I also do not understand what you mean with "they are like patterns for a function". Anyway it's not anymore an incorrect answer. To make it a good answer I would take a deeper look to the link in the comments above, and see which useful information/examples could be still missing. – Antonio Jul 05 '13 at 12:16