Stefan
Stefan

Reputation: 3859

How to pass multiple templates into a class

I have a class which needs two separate templates passed into it:

template <typename T>
class AwesomeClass
{
    TList *theList;
    typename list <T>::iterator theiterator;

  public:
    template <typename TList>
    AwesomeClass(TList &list)
    {
    theList = &list;
    };
}

As you can probably tell it essentially provides a wrapper for the STL (I have to do it this way). Ideally I do not want to pass both templates through at object declaration like this:

typedef AwesomeClass<int, BaseClass<int> > BaseClassIteratorInt;

and would rather get away with this:

typedef BaseClass<int> ListFromBaseClassInt;
typedef AwesomeClass<int> BaseClassIteratorInt;
BaseClassIteratorInt newInt(ListFromBaseClassInt)

(This is what the above code is meant to do)

However, I keep getting the error:

error C2143: syntax error : missing ';' before '*'

For the variable TList* theList.

I would need the to ctor to provide the type for TList, is there a way to do this?

Extra steps:

Okay, I now have code of the format:

template <typename Container>
class AwesomeClass
{
  public:
    typedef typename std::common_type< Container > value_type;

    bool firstUse;

    Container *theList;
    typename Container::iterator theIterator;
    explicit AwesomeClass(Container &list):theList(&list)
    {
    };
}

This is using common_type to get around a compiler bug which stop the line

typedef typename Container::value_type value_type;

compiling due to value_type not being a part of the global namespace.

But I have a compiler error for theIterator, the compiler claims that it needs a ';' before it.

Can anyone see what is wrong?

Upvotes: 0

Views: 296

Answers (4)

Felix Glas
Felix Glas

Reputation: 15524

You need to declare TList as a template parameter before you can use it in other declarations.

template <typename TList, typename T>
class AwesomeClass {
    TList* theList;

    /* ... */
};

Also you don't need to declare the second template parameter T, instead get the type like so:

using value_type = typename TList::value_type;

Secondly, you don't have to use template deduction in the ctor.

// template <typename TList> // Unnecessary if the template parameter is already declared
AwesomeClass(TList& list) {
    theList = &list;
}

Thirdly, you have put the semicolon after the ctor instead of at the end of the class scope.

/* ... */

AwesomeClass(TList& list) {
    theList = &list;
    }; // Unnecessary to put semicolon after function definitions.
} // Although, you need semicolon here.

It looks like you want to be able to automatically deduce the types of the template parameters when creating an object of AwesomeClass. However, class template parameters can not automatically be deduced, only function templates can do that.

To accomplish automatic deduction of template parameters you can create a function that returns a AwesomeClass with the deduced parameters, e.g.

template <typename TList>
auto make_awesome(TList& list) -> AwesomeClass<TList, typename TList::value_type> {
    return {list};
}

Edit:

If what you want is a class that stores a pointer to a std::list of any type then all you need to deduce is the element type. But then you can only store a pointer to a std::list container, not e.g. a pointer to std::vector.

template <typename T>
class AwesomeClass {
public:
    AwesomeClass(std::list<T>& c) {
        c_ = &c;
    }
private:
    std::list<T>* c_;
    typename std::list<T>::iterator iter_;
};

int main() {
    typedef AwesomeClass<int> BaseClassIteratorInt;
    BaseClassIteratorInt b{l};
}

Upvotes: 0

eerorika
eerorika

Reputation: 238311

I don't think you need two template params for that.

template <class Container>
class AwesomeClass {
public:
    // you can use this typedef to access the value type
    typedef typename Container::value_type value_type;
    AwesomeClass(Container &list): theList(&list) {}
private:
    Container *theList;
    typename Container::iterator theiterator;
};

int main() {
    // you can use typedef if you like
    typedef std::list<int> intList;
    intList list{1, 2, 3};
    AwesomeClass<intList> newInt(list);
}

Upvotes: 1

Jarod42
Jarod42

Reputation: 217145

With

template <typename T, typename TList> class AwesomeClass
class AwesomeClass
{
    TList *theList;
    typename list<T>::iterator theiterator;

public:
    explicit AwesomeClass(TList &list) : theList(&list) {}
};

What you can do to deduce type at construction is a free function:

template<typename T, typename TList>
AwesomeClass<T, TList> make_AwesomeClass(TList& tlist)
{
    return AwesomeClass<T, TList>(tlist);
}

Call it that way:

auto awesomeClass = make_AwesomeClass<int>(mylist);

Upvotes: 0

Pandrei
Pandrei

Reputation: 4951

it sound like you need a forward declaration for TList: you are using if before declaring it so the compiler can't know about it.

Upvotes: 0

Related Questions