Template functions and STL containers

S

Simon Elliott

Given a template function:

template <class T>
void foo(T& value)
{
// do something with value
}

Is there any way I can tell whether the type T is an STL container?

For example I'd like, within foo(), to treat "value" differently in
these two cases.


typedef std::vector<bar> barVector;
barVector myBarVector;
foo(myBarVector);

int i13 = 13;
foo(i13);

Normally I'd do a dynamic_cast to determine the type of value, but
because foo() doesn't know the type of the STL container, I can't do it:

template <class T>
void foo(T& value)
{
std::vector<???> test = dynamic_cast<std::vector<???>>(value);
if (test)
{
// It's a vector of ???
}
}

.... but if we're writing generic code, I don't know in advance what
'???' is.
 
V

Victor Bazarov

Simon said:
Given a template function:

template <class T>
void foo(T& value)
{
// do something with value
}

Is there any way I can tell whether the type T is an STL container?

Why do you think you need to?
For example I'd like, within foo(), to treat "value" differently in
these two cases.


typedef std::vector<bar> barVector;
barVector myBarVector;
foo(myBarVector);

int i13 = 13;
foo(i13);

Overload your function templates:

template<class T> void foo(T& v) ..
template<class T> void foo(vector<T>& v) ..

or specialise it/them.

V
 
S

Simon Elliott

Why do you think you need to?

See below.
Overload your function templates:

template<class T> void foo(T& v) ..
template<class T> void foo(vector<T>& v) ..

or specialise it/them.

Nice idea, and it would sort out the issue of trying to get a size from
a generic std::vector when I don't know what type it is containing.
Unfortunately my compiler doesn't like it.

The code looks a lot like this (I haven't run this snippet through the
compiler so there may be the odd typo):

template <class T> int fooCount(const T& value)
{
return(-1);
}

template <class T> int fooCount(const std::vector<T>& value)
{
return(value.size());
}

class fooBase
{
public:
virtual int GetCount()const=0;
};

template <class T> fooDerived
{
private:
T t_;
public:
virtual int GetCount()const
{
return(fooCount(t_));
}
};

Unfortunately when I try to create an instance of fooDerived like this:
typedef std::vector<bar> barVector;
fooDerived<barVector> myFooBar;

I get an error message saying "call to undefined function fooCount".
(Which is odd because you'd have thought it would have picked up the
first, more generic instance.)

I'm trying this on a fairly old compiler (Borland C++ builder 3) so I'm
not sure whether it's a C++ error or a compiler nonconformace. I will
try the above on BCB6 tomorrow.
 
S

Simon Elliott

Nice idea, and it would sort out the issue of trying to get a size
from a generic std::vector when I don't know what type it is
containing. Unfortunately my compiler doesn't like it.

But it would have done if I hadn't mis-spelled a function name.

Thanks for this: I didn't know you could split up the types on a
function overload.
 
S

Simon Elliott

But it would have done if I hadn't mis-spelled a function name.

Thanks for this: I didn't know you could split up the types on a
function overload.

Hmm. Tracing through the debugger shows that my vector overloaded
function is not being called:

template <class T> int fooCount(const std::vector<T>& value)

Instead, the more general function is being called:

template <class T> int fooCount(const T& value)

Not sure how to ensure that the correct function is being called.

In fact, even if I knew somehow that my type was a vector of some other
contained type, I'm not sure how to proceed given that I don't know
what that contained type is going to be.
 
V

Victor Bazarov

Simon said:
Hmm. Tracing through the debugger shows that my vector overloaded
function is not being called:

template <class T> int fooCount(const std::vector<T>& value)

Instead, the more general function is being called:

template <class T> int fooCount(const T& value)

Not sure how to ensure that the correct function is being called.

First of all, make sure that your compiler is not a faulty one. Below
is the code and the output I think it should produce (and it does with
at least one of the compilers I have here).
In fact, even if I knew somehow that my type was a vector of some other
contained type, I'm not sure how to proceed given that I don't know
what that contained type is going to be.

I don't know how you should proceed. You could try overloading your
function based on all _possible_ containers. You could also name those
functions differently (to be used in the derived classes differently).

Honestly, though. Just spend a bit more time tinkering, and you'll get
it, I am sure of it.

----------------------------
#include <iostream>
#include <vector>

template<class T> int getCount(T t)
{
return -1;
}

template<class T> int getCount(std::vector<T> const& vt)
{
return vt.size();
}

struct B
{
virtual int getCount() const = 0;
};

template<class T> struct D1 : B
{
int getCount() const { return ::getCount(db); }
T db;
};

struct D2 : B
{
int getCount() const { return ::getCount(db); }
int db;
};

int main()
{
B *b1 = new D1<std::vector<int> >;
B *b2 = new D2;
std::cout << "D1::getCount returned " << b1->getCount() << std::endl;
std::cout << "D2::getCount returned " << b2->getCount() << std::endl;
return 0;
}
---------------------------- output:
D1::getCount returned 0
D2::getCount returned -1
 
S

Simon Elliott

First of all, make sure that your compiler is not a faulty one. Below
is the code and the output I think it should produce (and it does with
at least one of the compilers I have here).

BCB3 and BCB6 won't even compile this. See below. Unfortunately BCB3
and BCB6 are compilers that this code needs to support. I'll see what
gcc makes of this code later today.
I don't know how you should proceed. You could try overloading your
function based on all possible containers. You could also name those
functions differently (to be used in the derived classes differently).

The problem is that the code is intended to be generic. I can easily
make it work if I know in advance the names of the classes the code is
required to accomodate.
Honestly, though. Just spend a bit more time tinkering, and you'll
get it, I am sure of it.

I'll get something that works. But I want something that's simple,
effective, easy to maintain. To achieve this I'll need to learn more
about templates. When I've got a few moments I think I need to have a
look at Andrei Alexandrescu's book.
----------------------------
#include <iostream>
#include <vector>

template<class T> int getCount(T t)
{
return -1;
}

template<class T> int getCount(std::vector<T> const& vt)
{
return vt.size();
}

struct B
{
virtual int getCount() const = 0;
};

template<class T> struct D1 : B
{
int getCount() const { return ::getCount(db); }

BCB3&6 error: Ambiguity between 'getCount(const
std::vector<int,std::allocator<int> >)' and 'getCount(const
 
S

Simon Elliott

I'll get something that works. But I want something that's simple,
effective, easy to maintain. To achieve this I'll need to learn more
about templates. When I've got a few moments I think I need to have a
look at Andrei Alexandrescu's book.

I didn't need to go that far: another RTFM of the std::vector docs
revealed a helpful feature: std::vector defines a typedef value_type
which you can use in templates to represent the type contained by the
vector.
 
V

Victor Bazarov

Simon Elliott said:
I didn't need to go that far: another RTFM of the std::vector docs
revealed a helpful feature: std::vector defines a typedef value_type
which you can use in templates to represent the type contained by the
vector.

I am sure you've seen this, but in case you haven't, every container in
the Standard library defines that type. So, you can even be relatively
container-independent...

Good luck! You're on the right track.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top