1

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.

Queueless
  • 113
  • 1
  • 7

5 Answers5

1

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;
}
Fernando N.
  • 6,369
  • 4
  • 27
  • 30
  • Yeah, I forgot to add those lines to the specialization's of the test method in my example, but they don't help. Thanks for the input though. – Queueless Oct 19 '09 at 11:24
  • Check if you are not missing something in your example. Fixing that line it compiles with gcc 4.4.1 and works ok. – Fernando N. Oct 19 '09 at 14:27
  • Well, they don't seem to make a difference with Microsoft's compiler, so it looks like a compiler conformance issue then. Thanks for for your input. – Queueless Oct 23 '09 at 17:12
0

You haven't qualified specific_body. Try

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

as your friend declaration.

Troubadour
  • 13,334
  • 2
  • 38
  • 57
0

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.

rz.
  • 1
  • 1
0

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.

sellibitze
  • 27,611
  • 3
  • 75
  • 95
  • I'm not sure why fulling specializing the `specific_body` class would matter in this case. I one case in my code declaring the body public helped, but I have another case where the `specfic_body` needs access to the private constructor of `interface` too; So I would like to solve the friend access issue, or restructure the code to achieve the same end where I can inherent from the body class. – Queueless Oct 16 '09 at 18:45
  • There is no way around full specialization to make it C++ standards compliant. If you don't get any errors on that part your compiler might support it as an extension, I don't know. But GCC rejects it. Just saying... – sellibitze Oct 16 '09 at 18:55
  • What exactly do you see as non-compliant here? Specializing just a member functon of a template class without specializing the entire class is perfectly legal in C++. Speaking informally, each member function of class template is by itself an independent template, which can be specialized independently. This is a rarely used feature, but it is there. 14.7.3/16 contains an example of such specialization. – AnT stands with Russia Oct 18 '09 at 08:43
  • He tries to specialize it without the template keyword – sellibitze Oct 18 '09 at 17:43
  • Oh, yeah, I missed it. I does indeed need the typical explicit specialization syntax with `template<>` bit. But still there's no need to "specialize the full class". – AnT stands with Russia Oct 19 '09 at 00:40
0

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

Queueless
  • 113
  • 1
  • 7