Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is pimpl compatible with anonymous namespaces?

I am trying to use the pimpl pattern and define the implementation class in an anonymous namespace. Is this possible in C++? My failed attempt is described below.

Is it possible to fix this without moving the implementation into a namespace with a name (or the global one)?

class MyCalculatorImplementation;

class MyCalculator
{
public:
    MyCalculator();
    int CalculateStuff(int);

private:
    MyCalculatorImplementation* pimpl;
};

namespace // If i omit the namespace, everything is OK
{
    class MyCalculatorImplementation
    {
    public:
        int Calculate(int input)
        {
            // Insert some complicated calculation here
        }

    private:
        int state[100];
    };
}

// error C2872: 'MyCalculatorImplementation' : ambiguous symbol
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}

int MyCalculator::CalculateStuff(int x)
{
    return pimpl->Calculate(x);
}
like image 330
anatolyg Avatar asked Apr 21 '11 14:04

anatolyg


3 Answers

No, the type must be at least declared before the pointer type can be used, and putting anonymous namespace in the header won't really work. But why would you want to do that, anyway? If you really really want to hide the implementation class, make it a private inner class, i.e.

// .hpp
struct Foo {
    Foo();
    // ...
private:
    struct FooImpl;
    boost::scoped_ptr<FooImpl> pimpl;
};

// .cpp
struct Foo::FooImpl {
    FooImpl();
    // ...
};

Foo::Foo() : pimpl(new FooImpl) { }
like image 149
Cat Plus Plus Avatar answered Sep 26 '22 02:09

Cat Plus Plus


Yes. There is a work around for this. Declare the pointer in the header file as void*, then use a reinterpret cast inside your implementation file.

Note: Whether this is a desirable work-around is another question altogether. As is often said, I will leave that as an exercise for the reader.

See a sample implementation below:

class MyCalculator 
{
public:
    MyCalculator();
    int CalculateStuff(int);

private:
    void* pimpl;
};

namespace // If i omit the namespace, everything is OK
{
    class MyCalculatorImplementation
    {
    public:
        int Calculate(int input)
        {
            // Insert some complicated calculation here
        }

    private:
        int state[100];
    };
}

MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}

MyCalaculator::~MyCalaculator() 
{
    // don't forget to cast back for destruction!
    delete reinterpret_cast<MyCalculatorImplementation*>(pimpl);
}

int MyCalculator::CalculateStuff(int x)
{
    return reinterpret_cast<MyCalculatorImplementation*>(pimpl)->Calculate(x);
}
like image 41
markshiz Avatar answered Sep 24 '22 02:09

markshiz


No, you can't do that. You have to forward-declare the Pimpl class:

class MyCalculatorImplementation;

and that declares the class. If you then put the definition into the unnamed namespace, you are creating another class (anonymous namespace)::MyCalculatorImplementation, which has nothing to do with ::MyCalculatorImplementation.

If this was any other namespace NS, you could amend the forward-declaration to include the namespace:

namespace NS {
    class MyCalculatorImplementation;
}

but the unnamed namespace, being as magic as it is, will resolve to something else when that header is included into other translation units (you'd be declaring a new class whenever you include that header into another translation unit).

But use of the anonymous namespace is not needed here: the class declaration may be public, but the definition, being in the implementation file, is only visible to code in the implementation file.

like image 38
Marc Mutz - mmutz Avatar answered Sep 27 '22 02:09

Marc Mutz - mmutz