简体   繁体   中英

C++ templated class and init in constructor

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<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, ie 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;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM