开发者

C++ templated class and init in constructor

开发者 https://www.devze.com 2023-03-17 18:56 出处:网络
I have a templated class, Foo : template <class A, class B> class Foo { public: Foo(A &aInstance);

I have a templated class, Foo :

template <class A, class B>
class Foo
{
public:
    Foo(A &aInstance);

private:
    Attr<Foo> _attr;
};

Then I have another templated class called Attr which is an attribute of my Foo class and which takes as template parameter the Foo class itself.

template <class C>
class Attr
{
    class SomeType
    {
        SomeType();
        ~SomeType();
    };

    Attr(const SomeType* st);
    ~Attr();

private:
    Attr();
}

I want to init _attr (of type Attr) in the constructor, casting the first parameter from the template as SomeType.

Foo constructor implementation :

template&开发者_JAVA百科lt;class A, class B>
Foo<A, B>::Foo(A &aInstance):
    _attr(
        (Attr<Foo<A, B> >::SomeType *) aInstance)
{

}

This won't compile :

error: expected primary-expression before ')' token

That error refers to the cast line in the Foo contructor implementation, as if SomeType was not recognized.

I now have an instance, but still got the same error.


template<class A, class B>
Foo<A, B>::Foo():
    _attr(
        (Attr<Foo<A, B> >::SomeType *) A)
{

}

A is a type, and you're trying to pass it to constructor. You need an instance here.


0)

(Attr<Foo<A, B> >::SomeType *) A)

at that point, A is a typename, i.e. the name of a type, thus, not anything you can cast.

1)

Also, Foo<A,B> is dependent upon A and B, therefore, Attr<Foo<A, B> > is a dependent name, too. Hence, you need a typename there so as to tell the compiler that SomeType is a type:

(typename Attr<Foo<A, B> >::SomeType *) somePointer)

2)

Furthermore, in C++, generally prefer C++-casts over C-style-casts. You'll catch a lot of mistakes with them. See also this tutorial :)

3)

On the other hand: Are you sure you need the cast by design, or should Attr point to exactly a Foo<A, B>?


First of all, the Attr class does not (in your snippet) use the C type, so you should explain where it is used, and what is the relation between C and SomeType.

Second, in this lines

Foo<A, B>::Foo():
    _attr(
        (Attr<Foo<A, B> >::SomeType *) A)

A is a type and not an object. If _attr should be initialized with the Foo object itself, then you should pass pointer this.

Foo<A, B>::Foo():
    _attr(
        (Attr<Foo<A, B> >::SomeType *) this)

However, that this point, the Foo object is not yet constructed, so beware what you do with the pointer in the Attr constructor.


Try changing your constructor to:

template<class A, class B>
Foo<A, B>::Foo(A &aInstance):
    _attr(
        (typename Attr<Foo<A, B> >::SomeType *) &aInstance) {}

You will, because you want a pointer, need to add an address-of operator in order to take the address of the instance object ... otherwise aInstance will not a pointer-type, instead it will be reference type which is effectively the same as passing the object itself (by reference), rather than a pointer to the object.


This works for me. A couple of typedefs help in making sense of templated code a little easier:

template<class C>
class Attr
{
public:
    class SomeType
    {
        SomeType();
       ~SomeType();
    };

    typedef typename Attr<C>::SomeType ReachIntoSomeType;

    Attr(const SomeType* st) { }
    ~Attr() { }

private:
    Attr();
};

template <class A, class B>
class Foo
{
public:
    Foo(A &aInstance) : _attr(reinterpret_cast<AttrOfFoo::ReachIntoSomeType*>(aInstance))     
    { }

private:
    typedef Attr<Foo> AttrOfFoo;
    AttrOfFoo _attr;
};
0

精彩评论

暂无评论...
验证码 换一张
取 消