Mihai
Mihai

Reputation: 1084

Incomplete type used in nested name specifier for Pimpl Idiom

I have this error for the following code

incomplete type ‘Foo::Pimpl’ used in nested name specifier

AnotherFoo.hpp

struct AnotherFoo {
    void methodAnotherFoo(Foo &);
};

AnotherFoo.cpp

#include "Foo.hpp"
#include "AnotherFoo.hpp"

void AnotherFoo::methodAnotherFoo(Foo &foo) {
    // here i want to save the function pointer of methodPimpl(), std::function for ex:
    std::function<void(void)> fn = std::bind(&Foo::Pimpl::methodPimpl, foo._pimpl); // <-- Here i am getting the error
}

Foo.hpp

struct Foo {
    Foo();
    class Pimpl;
    std::shared_ptr<Pimpl> _pimpl;
};

Foo.cpp

#include "Foo.hpp"

struct Foo::Pimpl {
    void methodPimpl(void) {}    
};

Foo::Foo() : _pimpl(new Pimpl) {}

main.cpp

#include "Foo.hpp"
#include "AnotherFoo.hpp"

int main() {
    Foo foo;
    AnotherFoo anotherFoo;
    anotherFoo.methodAnotherFoo(foo);
}

Does anyone have a good solution for how to fix this?

The main goal that I am trying to achieve is to keep the signature of the methodAnotherFoo method hidden from the header files.

Upvotes: 4

Views: 769

Answers (4)

Mihai
Mihai

Reputation: 1084

One solution that i found is to move the Pimpl implementation to AnotherFoo.cpp

Upvotes: -1

user7860670
user7860670

Reputation: 37513

Your Pimpl implementation is not correct. It should hide details while you are trying to access them directly from methodAnotherFoo. So you should make implementation details private and provide a public proxy methods to manipulate stored implementation:

class Foo
{
    public: Foo();

    public: void method(void);

    private: class Pimpl;
    private: std::shared_ptr<Pimpl> _pimpl;
};

// Foo.cpp
struct Foo::Pimpl
{
    void methodPimpl(void) {}    
};

Foo::Foo() : _pimpl(new Pimpl) {}

void Foo::method(void) {_pimpl->method();}

And change the rest of the code to utilize those proxy methods instead of digging to implementation details:

void AnotherFoo::methodAnotherFoo(Foo &foo)
{
    std::function<void(void)> fn = std::bind(&Foo::method, foo);
}

Upvotes: 0

SoronelHaetir
SoronelHaetir

Reputation: 15162

If AnotherFoo.cpp needs direct access to the implementation object it is going to have to see the definition of that type, there is no way around that. Perhaps add a "detail/foo.h" header that is meant for internal use like this.

Upvotes: 0

R Sahu
R Sahu

Reputation: 206577

The only file in which you may access details of Foo::Pimpl is Foo.cpp, the file in which it is defined.

You may not access it in AnotherFoo.cpp.

Your choices are:

  1. Change the implementation of AnotherFoo::methodAnotherFoo to use only the public interface of Foo.

  2. Move the implementation of AnotherFoo::methodAnotherFoo to Foo.cpp.

Upvotes: 4

Related Questions