Question

I'm trying to use the pimpl idiom to hide some grungy template code, but I can't give derived classes of the body class friend access to the handle class. I get an error C2248 from MSVC 9 sp1. Here's some code to duplicate the error:

//
// interface.hpp
//
namespace internal{
    template<class T>
    class specific_body;
}

class interface
{
    struct body;
    body *pbody_;
    interface(body *pbody);

    template<class T>
    friend class internal::specific_body;

public:

    ~interface();

    interface(const interface &rhs);

    bool test() const;

    static interface create( bool value );
};

//
// interface.cpp
//
struct interface::body
{
    virtual ~body(){}

    virtual bool test() const = 0;

    virtual interface::body *clone() const = 0;
};

class true_struct {};
class false_struct {};

namespace internal {

template< class T>
class specific_body : public interface::body
{ // C2248
public:

    specific_body(){}

    virtual bool test() const;

    virtual interface::body *clone() const
    {
        return new specific_body();
    }
};

bool specific_body<true_struct>::test() const
{
    return true;
}

bool specific_body<false_struct>::test() const
{
    return false;
}

} //namespace internal

interface::interface(body *pbody) : pbody_(pbody) {}

interface::interface(const interface &rhs) : pbody_(rhs.pbody_->clone()) {}

interface::~interface() { delete pbody_; }

bool interface::test() const
{
    return pbody_->test();
}

interface interface::create(bool value )
{
    if ( value )
    {
        return interface(new internal::specific_body<true_struct>());
    }
    else
    {
        return interface(new internal::specific_body<false_struct>());
    }
}

//
// main.cpp
//
// #include "interface.hpp"
//

int _tmain(int argc, _TCHAR* argv[])
{
    interface object( interface::create(true));

    if ( object.test() )
    {
        // blah
    }
    else
    {
    }
    return 0;
}

Any help would be appreciated, I'm trying to hide interface::body and specific_body implementations from the users of interface if that's not obvious from my question.

Was it helpful?

Solution 5

Well, I was able to "solve" this problem by making the body a public declaration in the interface. That solves the C2248 error during the declaration of the specific_body. I also made the body a friend to the interface class and added a method to the body struct:

static interface create( body *pbody )
{
    return interface(pbody);
}

so that a specific_body can create an interface if there is a nested relationship between instances of specific_body

OTHER TIPS

You need to add template<> in the explicit instantiation of the template test method

template<> // add this line
bool specific_body<true_struct>::test() const
{
    return true;
}

You haven't qualified specific_body. Try

template<class T>
friend class internal::specific_body;

as your friend declaration.

Try using typename maybe? I think I read in Sutter that typename will work to get to class inside of an unknown scope, while class won't.

In addition to the unqualified specific_body mentioned by Troubadour, your specialization attempt of specific_body<>::test for true_struct and false_struct seems incorrect. You have to specialice the full class.

To solve the problem, I'd simply declare body in the public section. Declaring specific_body to be a friend of interface::body in addition doesn't help either.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top