0

I have a class which has a template member functions and the private members needs to be put in the implementation class by pimpl idiom approach.

Foo.hpp

#include <iostream>
class Foo
{
public:
private:
    class FooImpl;
    std::unique_ptr<FooImpl> impl_;

public:
    Foo() = default;
    template <class F, class... Args>
    auto SomeFunction ( F &&f, Args &&...args) -> boost::unique_future<decltype (f(args...))>;
};

Foo.cpp

#include <Foo.hpp>
#include <FooImpl.hpp>
template <class... Args>
template <class F, class... Args>
auto SomeFunction ( F &&f, Args &&...args) -> boost::unique_future<decltype (f(args...))>
{
   impl->SomeFunction(std::forward<F>(f),std::forward<Args>(args)...);
}

FooImpl.hpp

#include <Foo.hpp>
class Foo::FooImpl
{
public:
    FooImpl() = default;
    template <class F, class... Args>
    auto SomeFunction ( F &&f, Args &&...args) -> boost::unique_future<decltype (f(args...))>;
private:
    int dummy;
};

FooImpl.cpp

#include <FooImpl.hpp>
template <class... Args>
template <class F, class... Args>
auto SomeFunction ( F &&f, Args &&...args) -> boost::unique_future<decltype (f(args...))>
{
   //Do Something...
}

I have tried the following approaches but nothing worked in my case:-

  1. With virtual functions. This didn't work because virtual functions cannot be templated.
  2. Explicitly instantiate all the template instances like
template class Foo<int>;
template class Foo<float>;

This won't suit in my case because any type can come in my function. I cannot explicitly instantiate all types.

Is there other approaches? Is it possible to implement pimpl idiom with template functions? Or is there any other alternative to pimpl idiom?

Tharani B
  • 21
  • 3
  • 4
    Isn't this intrinsically impossible? You want to avoid having to recompile clients when the implementation changes, but only those clients know the types to which you want to apply such a member function (template specialization). – Davis Herring Jan 24 '23 at 06:40
  • For you specific case you probably can do "callback" in `Foo` and call it from `FooImpl`. – sklott Jan 24 '23 at 06:59
  • One approach is to use *type erasure*: Use a public interface that is made out of templates and couple it with a private implementation that uses virtual methods, function pointers and void pointers. The templated front-end can use things like `std::any` and `std::function` to wrap arguments in a uniform way that the back-end can process – Homer512 Jan 24 '23 at 07:40
  • Not an answer because it's been ages since I worked with pimpls, but apart from not looking right, couldn't this be solved by putting the private template function in Foo.cpp instead of in FooImpl.cpp because the main point is that template functions need to be in the same translation unit as the caller and the only caller should be class Foo. Have a documented section stating that this is to overcome a limitation of C++. Correct me if I'm wrong, because it takes a bit too much time for me to verify it now. – stefaanv Jan 24 '23 at 07:44

0 Answers0