Template functions questions

  • Thread starter Bartholomew Simpson
  • Start date
B

Bartholomew Simpson

I'm trying to avoid (or at least, minimize) duplicity of effort. I have
the following function:

void Permissions::Exists(const unsigned int id,
std::vector<Permission>::const_iterator& iter)
{
if (m_permissions.empty())
iter = m_permissions.end() ;

std::vector<Permission>::const_iterator cit=m_permissions.begin();

for (cit; cit != m_permissions.end(); cit++)
{
if (cit->Id() == id)
break ;
}
iter = cit ;
}


It can take the ff combinations of args:

string, iter
string, const_iter
unsigned int, iter
unsigned int, const_iter


The logic is essentially the same for all cases - I would like to write
this as a template function, like:

template < class T1, class T2)
void Permissions::Exists(T1 key, T2 iterator_type)


I have the ff questions:

1). I don't ever recall seeing an iterator being passed as template
parameter (although I can't see why not - since it has a type) - is it
legal to use an iterator as a 'type' in a template func?


2). It appears like I may have to use template specialization (because I
am looking at different fields when doing the 'key comparison' - in
which case, my idea to use templates as "shorthand" (or as a compile
time code generator), is invalidated because I will still have to write
4 specializations ... am I thinking along the right lines, or am I
missing something (i.e. can I implement the above function as ONE
template function instead of four)?

3). last but not the least - a general template programming question
relating to 'const correctness' - is passing a const variable to a
template func treated as a different type from a non-const - i.e. if I
have the ff:

template <class T>
T foo(T var);

If I pass a const int variable to the function, and then in another part
of the code, pass a non-const int to the foo function - will the
compiler generate code for the two "functions"

const int foo(const int);
int foo(int);

(probably an ill posed question - but I hope you understand what I'm
getting at)
 
G

Gianni Mariani

Bartholomew Simpson wrote:
....
1). I don't ever recall seeing an iterator being passed as template
parameter (although I can't see why not - since it has a type) - is it
legal to use an iterator as a 'type' in a template func?

Any type may me used in a template as long as it conforms to the usage,
2). It appears like I may have to use template specialization (because I
am looking at different fields when doing the 'key comparison' - in
which case, my idea to use templates as "shorthand" (or as a compile
time code generator), is invalidated because I will still have to write
4 specializations ... am I thinking along the right lines, or am I
missing something (i.e. can I implement the above function as ONE
template function instead of four)?

Think of a parameter that may mean you don't need to specialize.
3). last but not the least - a general template programming question
relating to 'const correctness' - is passing a const variable to a
template func treated as a different type from a non-const - i.e. if I
have the ff:

template <class T>
T foo(T var);

If I pass a const int variable to the function, and then in another part
of the code, pass a non-const int to the foo function - will the
compiler generate code for the two "functions"

const int foo(const int);
int foo(int);

In general, pass a const reference for input parameters and whatever
makes sense for output parameters.

template <typename Key, typename Getter>
std::vector<Permission>::const_iterator
Permissions::Exists(const Key & id, const Getter &, getter)
{
std::vector<Permission>::const_iterator cit=m_permissions.begin();

for (cit; cit != m_permissions.end(); cit++)
{
if (cit->*Getter() == id)
return cit;
}
return m_permissions.end();
}

obj.Exists( 3, & Permission::Id );

Or, you can work it to have a syntax like:

obj.Exists<& Permission::Id>( 3 );

Either way, it makes little difference although the compiler may have an
easier time optimizing "obj.Exists<& Permission::Id>( 3 )".
 
M

Michael DOUBEZ

Bartholomew Simpson a écrit :
I'm trying to avoid (or at least, minimize) duplicity of effort. I have
the following function:

void Permissions::Exists(const unsigned int id,
std::vector<Permission>::const_iterator& iter)
{

What is m_permissions ? a globale ?
if (m_permissions.empty())
iter = m_permissions.end() ;

std::vector<Permission>::const_iterator cit=m_permissions.begin();

for (cit; cit != m_permissions.end(); cit++)
{
if (cit->Id() == id)
break ;
}
iter = cit ;
}


It can take the ff combinations of args:

string, iter
string, const_iter
unsigned int, iter
unsigned int, const_iter


The logic is essentially the same for all cases - I would like to write
this as a template function, like:

template < class T1, class T2)
void Permissions::Exists(T1 key, T2 iterator_type)


I have the ff questions:

1). I don't ever recall seeing an iterator being passed as template
parameter (although I can't see why not - since it has a type) - is it
legal to use an iterator as a 'type' in a template func?

STL is full of it.
You should even pass start and end of search as paremeter.
template <class InputIterator>
void Permissions::Exists(const unsigned int id,InputIterator& iter,
InputIterator& start, InputIterator& end);

An even better altenative would be to use the std::find_if algorithm.

struct Permissions::cmp_id :
std::binary_function<Permission,unsigned int,bool>
{
bool operator()(const Permission& perm, unsigned int id)
{
return perm.Id()==id;
}
};

vector<Permission>::iterator iter=find_if(start,end,
bind2nd(Permissions::cmp_id(), id));



Michael
 
B

Bartholomew Simpson

Gianni said:
template <typename Key, typename Getter>
std::vector<Permission>::const_iterator
Permissions::Exists(const Key & id, const Getter &, getter)

Is this correct?. What data type is the argument 'getter' ?

Lastly, the return type of the Exist() method as you have implemented
it, is a const_iterator - which may not always be appropriate. the
function is a utility function that is called by many other methods. I
may (for example), want to delete an item if it exists - in which case,
a const iterator is no good to me. This is why I wanted to 'templatize'
the iterator - because sometimes I want a non-const iterator (for when I
want to delete the found item), and other times, the const iterator is
ok, if I just need to verify that the item exists. Since C++ dosen't
allow function overloading based on return types alone, I had to pass
the iterator as a function argument.

So the correct signature should return a void and take an iterator type
as an input/output arg. The question remains - can I 'templatize' such a
function?
 
K

Kai-Uwe Bux

Bartholomew said:
I'm trying to avoid (or at least, minimize) duplicity of effort. I have
the following function:

void Permissions::Exists(const unsigned int id,
std::vector<Permission>::const_iterator& iter)
{
if (m_permissions.empty())
iter = m_permissions.end() ;

std::vector<Permission>::const_iterator cit=m_permissions.begin();

for (cit; cit != m_permissions.end(); cit++)
{
if (cit->Id() == id)
break ;
}
iter = cit ;
}


It can take the ff combinations of args:

string, iter
string, const_iter
unsigned int, iter
unsigned int, const_iter


The logic is essentially the same for all cases - I would like to write
this as a template function, like:

template < class T1, class T2)
void Permissions::Exists(T1 key, T2 iterator_type)


I have the ff questions:

1). I don't ever recall seeing an iterator being passed as template
parameter (although I can't see why not - since it has a type) - is it
legal to use an iterator as a 'type' in a template func?

Yes. It happens all the time. Have a look at the stuff provided by
<algorithm>. Most standard algorithms take iterator arguments. The iterator
type is then used as a template parameter.

2). It appears like I may have to use template specialization (because I
am looking at different fields when doing the 'key comparison' - in
which case, my idea to use templates as "shorthand" (or as a compile
time code generator), is invalidated because I will still have to write
4 specializations ... am I thinking along the right lines, or am I
missing something (i.e. can I implement the above function as ONE
template function instead of four)?

Depends. You might be able to minimize the code that needs to be specialized
by turning it into an accessor function that can be passed to other
functions as a function object parameter.

3). last but not the least - a general template programming question
relating to 'const correctness' - is passing a const variable to a
template func treated as a different type from a non-const - i.e. if I
have the ff:

template <class T>
T foo(T var);

If I pass a const int variable to the function, and then in another part
of the code, pass a non-const int to the foo function - will the
compiler generate code for the two "functions"

const int foo(const int);
int foo(int);

No. But that is nothing about templates. It just happens that

void f ( int i );

and

void f ( int const i );

are treated as identical function signatures. Think about it: would you
expect

void f ( int const param ) {}
...
int i = 5;
f(i);

to give a compiler error? After all, the variable i is passed by value and
the value 5 is about as const as it gets.


The difference between const and non-const only kicks in when you are
dealing with references. In that case, templates will also see the
difference:


typedef void (*f_ptr) ( void );

template < typename T>
void f ( void ) {}

template < typename T >
f_ptr g ( T t ) {
return ( &f<T> );
}

template < typename T >
f_ptr h ( T & t ) {
return ( &f<T> );
}

int main ( void ) {
int i = 0;
int const ci = 0;
{
bool no_distinction = ( g(i) == g(ci) );
if ( no_distinction ) {
std::cout << "one function generated\n";
} else {
std::cout << "two fucntions generated\n";
}
}
{
bool no_distinction = ( h(i) == h(ci) );
if ( no_distinction ) {
std::cout << "one function generated\n";
} else {
std::cout << "two fucntions generated\n";
}
}
}




Best

Kai-Uwe Bux
 
G

Gianni Mariani

Bartholomew said:
Is this correct?. What data type is the argument 'getter' ?

Try it and see.
Lastly, the return type of the Exist() method as you have implemented
it, is a const_iterator - which may not always be appropriate.


Maybe a const and non const methods would be better.

....
So the correct signature should return a void and take an iterator type
as an input/output arg. The question remains - can I 'templatize' such a
function?

Returning a void is not always the best way.
 

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

No members online now.

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top