Andak
Andak

Reputation: 144

template class variable as member of a non template class

I'm not an expert C++ developer, I'm not sure if is it possible to do what I want.

I have a template class like:

template < typename T >
class table
{
public
table ( AnotherClassPtr* handler, int s);
table<T>& operator<<(const T& table);
table<T>& operator>>( T& table);

...
}

I have a standard class. In this class I would like to create some members that are table objects. es:

class A{
public:
 ...
AnotherClassPtr* pointer;
table<aCertainStruct> myTable;
...
}

It does not work because I miss the default constructor of table. But I can't make a default constructor because I need to pass to the table class a pointer to AnotherClassPtrwhich is created in the constructor of class A just before where i would like to call the constructor I defined for table. es:

//inside the constructor of the A class.
....
pointer= getAnotherClassPtr();
table<aCertainStruct> myTable ( pointer, 42);
...

[an attempt] The stuff below compile but it does not work as I expected. Infact if I try to call some funcions of the class table it does not work.

class A{
public:
 ...
AnotherClassPtr* pointer;
table<aCertainStruct> myTable ( AnotherClassPtr*, unsigned int)
...
}

// in the constructor of the A class
....
pointer= getAnotherClassPtr();
table<aCertainStruct> myTable ( pointer, 42);
...

as I said this does not work;

Q: is it possible to create a template class variable as member of a non template class? Or in other workds: is it possible to define a table member in the A class declaration and then define the table object calling my user defined constructor inside the A constructor?

I'm sorry for my bad english, is not my native language, I hope the problem is clear.

thanks in advance.

Upvotes: 0

Views: 892

Answers (2)

aschepler
aschepler

Reputation: 72473

In simple cases like this, you can use the member initializer syntax rather than assigning to (already initialized) members.

class A
{
public:
    A() :
        pointer(getAnotherClassPtr()),
        myTable(pointer, 42)
    {}

    //...
    // pointer must come before myTable!
    AnotherClassPtr* pointer;
    table<aCertainStruct> mytable;
};

As noted in the class comment, this wouldn't work if mytable were declared before pointer in the class definition. The order class members are initialized always depends on the order the class declared them, not the order of the constructor's member initializer list. Also, if getAnotherClassPtr is a member of A, make sure it's either marked static or it doesn't use any other members of A declared before pointer, for the same reason.

If you have other reasons to want class members declared in a certain order, or if the initialization logic is more complicated in other ways, a more general solution to this sort of issue is to use a private helper struct and delegate to a private constructor:

class A
{
private:
    struct InitHelper;
public:
    A() : A(InitHelper()) {}
    // ...

    // Now member order doesn't matter.
    table<aCertainStruct> mytable;
    AnotherClassPtr* pointer;
    // ...

private:
    explicit A(InitHelper&& helper);
};

struct A::InitHelper
{
    AnotherClassPtr* pointer;
    unsigned int mytable_arg2;
    InitHelper();
};

inline A::InitHelper::InitHelper()
{
    // Actual logic here!
    // ...
    pointer = getAnotherClassPtr();
    mytable_arg2 = 42;
    // ...
}

inline A::A(InitHelper&& helper) :
    mytable_arg2(helper.pointer, helper.mytable_arg2),
    pointer(helper.pointer)
{}

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409472

That's why there exists constructor initializer lists:

class A{
public:
    A()
        : pointer(getAnotherClassPtr()), myTable(pointer, some_value)
    {}

    ...
    AnotherClassPtr* pointer;
    table<aCertainStruct> myTable;
    ...
};

This will initialize and "call" the parameterised constructor of table, instead of the default constructor.


These days with a relatively modern compiler, you should also be able to do something similar to what you want in the second attempt of the A class, but you have to use "assignment" syntax for the initialization, or curly-braces {} instead of parentheses () (since parentheses are for member functions):

table<aCertainStruct> myTable{pointer, some_value};

This of course requires that pointer is initialized first.

Upvotes: 1

Related Questions