Note: Please take a moment and read the entire question if you are tempted to mark this as a duplicate. I have myself referenced the other related questions below but those questions are very much at the C++ language level. This question is at the C++ language level too but this question is also about API development for APIs involving templates that other questions do not seem to address.
I am exposing an API that to my users (client code). My API relies a lot on templates.
What does not work
Here is my API code:
// api.h
#include <vector>
template<typename T> void api_func(std::vector<T> v);
// api.cpp
#include <iostream>
#include <vector>
template<typename T> void api_func(std::vector<T> v)
{
// This prints just the size, but in the actual API, we would be
// doing more complex things.
std::cout << v.size() << '\n';
}
Here is a possible client code:
// client.cpp
#include "api.h"
int main()
{
std::vector<int> v {1, 2, 3, 4, 5};
// Although this client is calling the API with a std::vector<int>
// another client may call the API with another vector type such as
// std::vector<std::string>.
api_func(v);
}
Of course, this does not compile.
$ clang++ -std=c++11 api.cpp client.cpp
Undefined symbols for architecture x86_64:
"void api_func<int>(std::__1::vector<int, std::__1::allocator<int> >)", referenced from:
_main in client-2a152c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
What works
This issue has been discussed extensively on Stack Overflow already in the following posts:
- Why can templates only be implemented in the header file?
- Why do C++ template definitions need to be in the header?
- Define template in header file and definition in a cpp file within derived class
According to those discussions, one way to fix the issue is by moving the template definition to header file too.
// api.h - fixed
#include <iostream>
#include <vector>
template<typename T> void api_func(std::vector<T> v)
{
// This prints just the size, but in the actual API, we would be
// doing more complex things.
std::cout << v.size() << '\n';
}
# api.cpp is unnecessary now
rm api.cpp
# client.cpp remains the same
This does compile now.
$ clang++ -std=c++11 client.cpp && ./a.out
5
Questions
The resolution shows that if I don't want to commit to specific types for the template parameters in my API (to ensure that the client has the flexibility to choose types appropriate to their needs), then any functions relying on template parameters need to be defined in the header file itself.
But when I do this for all functions in my API, it appears that all my business logic has moved to the header file. So my entire API is now a giant collection of .H files with absolutely no .CPP files.
My questions:
- Am I doing something wrong that has caused my entire API implementation to be composed only of .H files and no .CPP files?
- How are APIs like these generally designed? Are there any other techniques to bring back implementation code into .CPP files such that only minimum possible stuff goes into .H files?