By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,972 Members | 883 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,972 IT Pros & Developers. It's quick & easy.

Template functions questions

P: n/a
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)


Jun 19 '07 #1
Share this Question
Share on Google+
6 Replies


P: n/a
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 )".
Jun 19 '07 #2

P: n/a
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
Jun 19 '07 #3

P: n/a


Gianni Mariani wrote:
>
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?
{
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 )".
Jun 19 '07 #4

P: n/a


Michael DOUBEZ wrote:
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 ?
A static member variable

Jun 19 '07 #5

P: n/a
Bartholomew Simpson wrote:
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
Jun 19 '07 #6

P: n/a
Bartholomew Simpson wrote:
>

Gianni Mariani wrote:
>>
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' ?
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.
Jun 19 '07 #7

This discussion thread is closed

Replies have been disabled for this discussion.