Function overloading and template - c++

I have an overloaded function, their definitions are the same and only one parameter change.
So, I tried to create a template function but when I call it I got a symbol lookup error.
Header file
void func(Myobject obj);
void func(MySecondObject obj);
Source file
template<typename T>
void func(T obj) { obj.foo(); }
Test file
#include "MyHeaderFile.h"
func(MySecondObject()); // symbol lookup error at runtime
Thanks.

If you say
void func(Myobject obj);
void func(MySecondObject obj);
then you promise to the compiler that it will eventually find
void func(Myobject obj)
{ /* implementation */ }
void func(MySecondObject obj)
{ /* implementation */ }
Since you didn't provide these implementations (there are no definitions for these symbols you declared), you get an error.
What you can do however is this:
Header file
void func(Myobject obj);
void func(MySecondObject obj);
Source file
template<typename T>
void func_impl(T obj) { obj.foo(); }
void func(Myobject obj) { func_impl(obj); }
void func(MySecondObject obj) { func_impl(obj); }
This allows you to declare and define "real" (non-templated) functions for your users, but you can still implement all of them by delegating the work to the same template function. It is best practice to put the func_impl into an unnamed namespace (namespace /* no name here */ { /* code goes here */ }) which will make it internal to that translation unit (and also makes it clear that it's not intended to be seen/used by other code, without having to cross-reference the header).
(The following is already discussed at Why can templates only be implemented in the header file?).
An alternative approach is to declare the function template in the header, then define it in the source file and provide explicit instantiations for the types you want:
Header file
template<class T>
void func(T obj);
// Explicit instantiation declarations
extern template void func<Myobject>(Myobject obj);
extern template void func<MySecondObject>(MySecondObject obj);
Source file
template<typename T>
void func(T obj) { obj.foo(); }
// Explicit instantiation definitions
template void func<Myobject>(Myobject obj);
template void func<MySecondObject>(MySecondObject obj);
This approach is significantly more verbose, potentially confusing for users that are not template-affine, and trying to use it with the wrong type leads to linker errors instead of a nicer compiler error, so the first solution above can easily be the most appropriate.
Or you could define the entire template in the header file. There can be good reasons to avoid that though.

It seems that you want to have a template function with two explicit instantiations for MyObject and MySecondObject. Template function declaration should be in your header like that:
template<typename T>
void func(T obj);
Then in the corresponding source file you should provide generic implementation + explicit instantiations:
#include "header.hpp"
template<typename T>
void func(T obj)
{
obj.foo();
}
template void func<MyObject>(MyObject obj);
template void func<MySecondObject>(MySecondObject obj);
Then you can use that two versions in your code:
func(MyObject());
func(MySecondObject());
but call to func with another template parameter, e.g. func('c') will result in undefined reference.
cpp reference section "Explicit instantiation".

I would suggest defining the template specializations in the source file. It hides the template specializations in the current translation unit.
MyHeaderFile.h
template <typename T>
void func(T obj);
MyHeader.cpp
#include <iostream>
#include "MyHeaderFile.h"
template <typename T>
void func(T obj)
{
std::cout << "function name: " << __func__;
}
template void func<MySecondObject>(MySecondObject obj);
template void func<Myobject>(Myobject obj);
I hope this answer solves your problem.

Related

Separate compilation model for libraries that use templates [duplicate]

Suppose that I have two template functions declared in a header file:
template <typename T> void func1(const T& value);
template <typename T> void func2(const T& value);
And suppose that the implementation of these functions (also in a header file and not in a source file, because they are templates) uses some implementation helper function, which is also a template:
template <typename T> void helper(const T& value) {
// ...
}
template <typename T> void func1(const T& value) {
// ...
helper(value);
}
template <typename T> void func2(const T& value) {
// ...
helper(value);
}
In any source file that I include the header file, the helper function will be visible. I don't want that, because the helper function is just an implementation detail. Is there a way to hide the helper function?
A common approach (as used in many Boost libraries, for example) is to put the helper in a namespace called details, possibly in a separate header (included from the "public" header).
There's no way to prevent it from being visible, and callable, but this quite clearly indicates that it is part of the implementation, not the interface.
The established precedent is to put that sort of thing in a specially (i.e. consistently) named nested namespace. Boost uses namespace details, Loki uses namespace Private. Obviously nothing can prevent anyone from using the contents of those namespaces, but both names convey the meaning that their contents aren't intended for general consumption.
That being said, an easy alternative is to turn func1 and func2 from free function templates into static member function templates of some common class; this way, helper can simply be a private member of said class, invisible to the outside world:
struct funcs {
template<typename T>
static void func1(T const& value) {
// ...
helper(value);
}
template<typename T>
static void func2(T const& value) {
// ...
helper(value);
}
private:
template<typename T>
static void helper(T const& value) {
// ...
}
};
Two options off the top of my head:
Move all the implementation to an hpp file which you include at the bottom of your h file.
Refactor your code as class templates, then make the helpers private.
Since the user of your code needs to see the full definition of the func1 function, its implementation, nor its helper function implementation, cannot be hidden.
But if you move the implementation into another file, the user will only have to be confronted with the template declaration:
//templates.h
template< typename T > void f1( T& );
#include <templates_impl.h> // post-inclusion
And the definition:
// templates_impl.h
template< typename T > void f1_helper( T& ) {
}
template< typename T > void f1( T& ) {
// the function body
}
In C++20 you can now use modules.
For this you could create a module some_module.cppm holding all functions and marking only the interface (either the individual functions or a namespace) with export while not exposing the helper functions:
// some_module.cppm
export module some_module;
template <typename T>
void helper(const T& value) {
// ...
}
export
template <typename T>
void func1(const T& value) {
// ...
helper(value);
}
export
template <typename T>
void func2(const T& value) {
// ...
helper(value);
}
In the case above only the functions func1 and func2 are exported and can be accessed inside main.cpp:
// main.cpp
#include <cstdlib>
import some_module;
int main() {
func1(1.0);
func2(2.0);
return EXIT_SUCCESS;
}
In clang++12 you can compile this code with the following three commands:
clang++ -std=c++2b -fmodules-ts --precompile some_module.cppm -o some_module.pcm
clang++ -std=c++2b -fmodules-ts -c some_module.pcm -o some_module.o
clang++ -std=c++2b -fmodules-ts -fprebuilt-module-path=. some_module.o main.cpp -o main
./main
I would (as said before) make a template class, make all functions static and the helper function private. But besides that I'd also recommend making the constructor private as shown below:
template <typename T>
class Foo{
public:
static void func1(const T& value);
static void func2(const T& value);
private:
Foo();
static void helper(const T& value);
}
When you make the constructor private, the compiler won't allow instances of this template class. So the code below would become illegal:
#include "foo.h"
int main(){
int number = 0;
Foo<int>::func1(number); //allowed
Foo<int>::func2(number); //allowed
Foo<int>::helper(number); //not allowed, because it's private
Foo<int> foo_instance; //not allowed, because it's private
}
So why would someone want this? Because having different instances that are EXACTLY the same is something you probably never want. When the compiler tells you that the constructor of some class is private, then you can assume that having different instances of it would be unnecesarry.
I know you mean that you want to hide it so finely that callers have no way to find your helper functions as long as they don't change your code file. I know it so well because I have very similar needs recently.
So how about wrapping your helper functions in an anonymous namespace? This is recently the most elegant style I found:
namespace YourModule
{
namespace
{//Your helper functions}
//Your public functions
}
This practice effectively hides your internal functions from the outside. I can't find any way that a caller can access functions in anonymous namespaces.
It's usually not a good practice, as answered by #user3635700 , to convert your namespace to a class full of static functions, especially when you have templates of static variables like:
template <uint8_t TimerCode>
static uint16_t MillisecondsElapsed;
If this variable appears in a class, you'll have to initialize it somewhere outside the class! However, you can't do it because it's a template! WTF!
It seems that an anonymous namespace in the header file, which is criticized by some, is the only and the most perfect solution to our needs.

Template explicit instantiation in header

I know that it's possible to declare a template in the header and its definition in a source file as long as I declare in advance the parameters it will be instantiated with. My question is: will putting the explicit instantiations in the .h file create problems? It seems to work but I've always seen people putting them in the source file, not in the .h
What I have in mind is the following
.h file
class foo
{
public:
template <typename T>
void do(const T& t);
};
template<> void foo::do<int>(const int&);
template<> void foo::do<std::string>(const std::string&);
.cpp file
template <int>
void foo::do(const int& t)
{
// Do something with t
}
template <std::string>
void foo::do(const std::string& t)
{
// Do something with t
}
These are called explicit specializations. Explicit instantiation is something else.
Putting those declarations in the header file is fine, and a very good idea. When compiling other source files, you want the compiler to know not to generate those specializations using the primary template.
Your syntax in the *.cpp file is wrong, though. The definitions should be more like the declarations:
template <>
void foo::do<int>(const int& t)
{
// Do something with t
}

What is the correct syntax to define specializations of template method

Say I declared a class with a template method.
class MyClass {
...
template<typename T> void myMethod(const T& obj);
}
I have defined a generic version of the method
template<typename T>
void MyClass::myMethod(const T& obj) { .... }
and want to define several specializations for various types. What is the correct syntax? VS2013 compiler does not seem to approve my attempts.
template<>
void MyClass::myMethod<int>(const int &) {....}
or
template<int>
void MyClass::myMethod(const int &) { .... }
The first syntax is ok, as a specialization. The second is wrong as it is defining a template<int> while myMethod is declared as a template<typename>. But keep in mind that a specialization isn't needed at all, an overload is just fine, like
class MyClass {
void myMethod(const int& obj) { ... }
// ... more overloads
};
Of course, if you need to separate declarations from definitions (which I avoid for templates), this leads to more code duplication. Depending on type, this way you may also enforce call by value, e.g.
void myMethod(bool obj) { ... }
which does not apply to your specializations.

function template explicit instantiation extern

I have a function which has exactly the same code for many basic types. To save code lines, I want to declare it as template and instantiate it explicitly for all later used types once: declaration in header file and implementation + explicit instantiation in cpp file (same design as writing normal function bibs).
My approach was:
// header.h
template <class T> T func (T arg);
// header.cpp
#include "header.h"
template <class T> T func (T arg)
{
// implementation...
}
template int func<int> (int arg);
template double func<double> (double arg);
However, on parashift, I found this form of declaration:
// header.h
template <typename T> extern void foo();
What is the sense of extern here? How differs it from my approach? What is correct?
Also normal functions never have to be declared extern. It would be different if it was extern template void foo<int>(); (see accepted answer here), what would prohibit the compiler to instatiate a template that is already implemented in the header file.
Edit:
Is
// header.h
int func (int arg);
double func (double arg);
// header.cpp
#include "header.h"
int func (int arg)
{ ... }
double func (double arg)
{ ... }
not completely analogous/equivalent to
// header.h
template <class T> T func (T arg);
// here is the question: like above or template <class T> extern T func (T arg); ???
// header.cpp
#include "header.h"
template <class T> T func (T arg)
{ ... }
template int func<int> (int arg);
template double func<double> (double arg);
concerning later usage
// main.cpp
#include "header.h"
int main ()
{
// for overloading
func(20);
func(20.0);
func((int)20.0);
// for template
func(20); // == func<int>(20)
func(20.0); // == func<double>(20.0)
func((int)20.0); // == func<int>((int)20.0)
func<int>(20.0); // == func<int>((int)20.0)
return 0;
}
Your syntax is declaring in the header file that there exists somewhere a template <class T> T func (T arg); which would still not let user have the code using that template function, but would let having template code doing that (which compiler won't be able to instantiate without having seen the template function definition).
The FAQ section you refer to is featuring the syntax declaring that there exists an instantiation of template for certain class X somewhere and the compiler, when seeing X x = func(X()); should not be instantiating a template but rather leave the symbol unresolved and let linker deal with it.

How to hide an implementation helper template?

Suppose that I have two template functions declared in a header file:
template <typename T> void func1(const T& value);
template <typename T> void func2(const T& value);
And suppose that the implementation of these functions (also in a header file and not in a source file, because they are templates) uses some implementation helper function, which is also a template:
template <typename T> void helper(const T& value) {
// ...
}
template <typename T> void func1(const T& value) {
// ...
helper(value);
}
template <typename T> void func2(const T& value) {
// ...
helper(value);
}
In any source file that I include the header file, the helper function will be visible. I don't want that, because the helper function is just an implementation detail. Is there a way to hide the helper function?
A common approach (as used in many Boost libraries, for example) is to put the helper in a namespace called details, possibly in a separate header (included from the "public" header).
There's no way to prevent it from being visible, and callable, but this quite clearly indicates that it is part of the implementation, not the interface.
The established precedent is to put that sort of thing in a specially (i.e. consistently) named nested namespace. Boost uses namespace details, Loki uses namespace Private. Obviously nothing can prevent anyone from using the contents of those namespaces, but both names convey the meaning that their contents aren't intended for general consumption.
That being said, an easy alternative is to turn func1 and func2 from free function templates into static member function templates of some common class; this way, helper can simply be a private member of said class, invisible to the outside world:
struct funcs {
template<typename T>
static void func1(T const& value) {
// ...
helper(value);
}
template<typename T>
static void func2(T const& value) {
// ...
helper(value);
}
private:
template<typename T>
static void helper(T const& value) {
// ...
}
};
Two options off the top of my head:
Move all the implementation to an hpp file which you include at the bottom of your h file.
Refactor your code as class templates, then make the helpers private.
Since the user of your code needs to see the full definition of the func1 function, its implementation, nor its helper function implementation, cannot be hidden.
But if you move the implementation into another file, the user will only have to be confronted with the template declaration:
//templates.h
template< typename T > void f1( T& );
#include <templates_impl.h> // post-inclusion
And the definition:
// templates_impl.h
template< typename T > void f1_helper( T& ) {
}
template< typename T > void f1( T& ) {
// the function body
}
In C++20 you can now use modules.
For this you could create a module some_module.cppm holding all functions and marking only the interface (either the individual functions or a namespace) with export while not exposing the helper functions:
// some_module.cppm
export module some_module;
template <typename T>
void helper(const T& value) {
// ...
}
export
template <typename T>
void func1(const T& value) {
// ...
helper(value);
}
export
template <typename T>
void func2(const T& value) {
// ...
helper(value);
}
In the case above only the functions func1 and func2 are exported and can be accessed inside main.cpp:
// main.cpp
#include <cstdlib>
import some_module;
int main() {
func1(1.0);
func2(2.0);
return EXIT_SUCCESS;
}
In clang++12 you can compile this code with the following three commands:
clang++ -std=c++2b -fmodules-ts --precompile some_module.cppm -o some_module.pcm
clang++ -std=c++2b -fmodules-ts -c some_module.pcm -o some_module.o
clang++ -std=c++2b -fmodules-ts -fprebuilt-module-path=. some_module.o main.cpp -o main
./main
I would (as said before) make a template class, make all functions static and the helper function private. But besides that I'd also recommend making the constructor private as shown below:
template <typename T>
class Foo{
public:
static void func1(const T& value);
static void func2(const T& value);
private:
Foo();
static void helper(const T& value);
}
When you make the constructor private, the compiler won't allow instances of this template class. So the code below would become illegal:
#include "foo.h"
int main(){
int number = 0;
Foo<int>::func1(number); //allowed
Foo<int>::func2(number); //allowed
Foo<int>::helper(number); //not allowed, because it's private
Foo<int> foo_instance; //not allowed, because it's private
}
So why would someone want this? Because having different instances that are EXACTLY the same is something you probably never want. When the compiler tells you that the constructor of some class is private, then you can assume that having different instances of it would be unnecesarry.
I know you mean that you want to hide it so finely that callers have no way to find your helper functions as long as they don't change your code file. I know it so well because I have very similar needs recently.
So how about wrapping your helper functions in an anonymous namespace? This is recently the most elegant style I found:
namespace YourModule
{
namespace
{//Your helper functions}
//Your public functions
}
This practice effectively hides your internal functions from the outside. I can't find any way that a caller can access functions in anonymous namespaces.
It's usually not a good practice, as answered by #user3635700 , to convert your namespace to a class full of static functions, especially when you have templates of static variables like:
template <uint8_t TimerCode>
static uint16_t MillisecondsElapsed;
If this variable appears in a class, you'll have to initialize it somewhere outside the class! However, you can't do it because it's a template! WTF!
It seems that an anonymous namespace in the header file, which is criticized by some, is the only and the most perfect solution to our needs.