Reputation: 406
In my code usually I have to write a function that takes a "Path-like" type, that is, something that I can convert to boost::filesystem::path
, for example
QString
std::string
const char *
in A.hpp
struct A
{
template <typename PathLike>
void myFunction(PathLike path);
};
in A.cpp
template <typename PathLike>
void A::myFunction(PathLike path)
{
boost::filesystem::Path p = convertToBoostPath(path);
//do something...
}
//Explicit instantiations needed
template void A::myFunction(string);
template void A::myFunction(QString);
template void A::myFunction(char const *);
//....
The problem is that if I want to do the same thing in a different function B
, I need to add the explicit instantiations all over again. Maybe I'm taking a wrong approach.
Upvotes: 2
Views: 116
Reputation: 217075
How about create a class PathLike
and use it:
class PathLike
{
public:
explicit PathLike(const QString& path) : mPath(convertToBoostPath(path)) {}
explicit PathLike(const std::string& path) : mPath(convertToBoostPath(path)) {}
explicit PathLike(const char* path) : mPath(convertToBoostPath(path)) {}
PathLike(const boost::filesystem::path& path) : mPath(path) {}
const boost::filesystem::path& get() const { return mPath;}
operator const boost::filesystem::path&() const { return mPath;}
private:
boost::filesystem::path mPath;
};
(I mark other constructor explicit to promote filesystem::path
, but up to you to add/remove explicit
).
And then:
struct A
{
void myFunction(PathLike path)
{
boost::filesystem::path p = path;
//do something...
}
};
Upvotes: 1
Reputation: 136208
One way to explicitly instantiate a function template for a pack of types is to take the address of each function instantiation. E.g.:
template<class... Ts>
void instantiate_myFunction() {
auto f = [](auto&&) { return 1; };
auto initializer_list = { f(&A::myFunction<Ts>)... };
static_cast<void>(initializer_list);
}
int main() {
instantiate_myFunction<std::string, char const*>();
}
Upvotes: 0
Reputation: 23681
Instead of writing a template function that takes any PathLike
and also does the real work, write a template function that takes any PathLike
, converts it to boost::filesystem::Path
as shown, then calls a non-template function (whose definition can be in the .cpp) which will do the real work.
In A.hpp
:
class A
{
public:
template <typename PathLike>
void myFunction(PathLike path);
private:
void myFunctionImpl(boost::filesystem::Path path);
};
template <typename PathLike>
void A::myFunction(PathLike path)
{
myFunctionImpl(convertToBoostPath(path));
}
In A.cpp
:
void A::myFunctionImpl(boost::filesystem::Path path)
{
// do something...
}
This has the added benefit that misuse of the interface results in compiler errors, not linker errors.
Upvotes: 3