templated function help

F

Francesco Montorsi

Hi,
I'm quite new to templates... I was asked to transform the following macro

#define DECLARE_STRING_CHECK(func) \
inline bool func##String(const MyString& val) \
{ \
for ( MyString::const_iterator i = val.begin(); \
i != val.end(); \
++i ) \
if (func(*i) == 0) \
return false; \
return true; \
}

DECLARE_STRING_CHECK(isalpha) // declares isalphaString()
DECLARE_STRING_CHECK(isalnum)
DECLARE_STRING_CHECK(isdigit)

in a template.
I blindly tried:

template<typename T>
inline bool StringCheck(const MyString& val)
{
for ( MyString::const_iterator i = val.begin();
i != val.end();
++i )
if (T(*i) == 0)
return false;
return true;
}

Needless to say it doesn't work. I.e. if I write

if (!StringCheck<isalpha>(str))
return false;

I get "error: no matching function for call to ‘StringCheck(const MyString&)’"
with GCC...

Can you help me with some hints :) ?

Thanks!!
Francesco
 
D

Daniel Pitts

Francesco said:
Hi,
I'm quite new to templates... I was asked to transform the following
macro

#define DECLARE_STRING_CHECK(func) \
inline bool func##String(const MyString& val) \
{ \
for ( MyString::const_iterator i = val.begin(); \
i != val.end(); \
++i ) \
if (func(*i) == 0) \
return false; \
return true; \
}

DECLARE_STRING_CHECK(isalpha) // declares isalphaString()
DECLARE_STRING_CHECK(isalnum)
DECLARE_STRING_CHECK(isdigit)

in a template.
I blindly tried:

template<typename T>
inline bool StringCheck(const MyString& val)
{
for ( MyString::const_iterator i = val.begin();
i != val.end();
++i )
if (T(*i) == 0)
return false;
return true;
}

Needless to say it doesn't work. I.e. if I write

if (!StringCheck<isalpha>(str))
return false;

I get "error: no matching function for call to ‘StringCheck(const
MyString&)’" with GCC...

Can you help me with some hints :) ?

Thanks!!
Francesco
I tried this in GCC.

template<int (T)(int)>
inline bool check(char * const str) {
return T(str[0]) == 0;
}

check<isalpha>("Foo"); seemed to work fine
 
S

SG

template<typename T>
     inline bool StringCheck(const MyString& val)
     {
         for ( MyString::const_iterator i = val.begin();
               i != val.end();
               ++i )
             if (T(*i) == 0)
                 return false;
         return true;
     }

Needless to say it doesn't work. I.e. if I write

if (!StringCheck<isalpha>(str))
    return false;

"isalpha" is not a type. There are several possibilities:

template<int (&T)(int)> // T is a reference to a function
int foo() { // with *external* linkage.
return T(42);
}

int main() { foo<isalpha>(); }

But this way you can only use functions with the exact same signature
and only functions that have external linkage. You can also make T a
type for a function pointer (or function object) and pass the pointer
(or object) as additional parameter. This would be the "STL style":

template<typename T> // T is type (function pointer
int foo(T some_func) { // or function object)
return some_func(42);
}

int main() { foo(isalpha); } // function decays to pointer

HTH,
SG
 
F

Francesco Montorsi

Daniel Pitts ha scritto:
I tried this in GCC.

template<int (T)(int)>
inline bool check(char * const str) {
return T(str[0]) == 0;
}

check<isalpha>("Foo"); seemed to work fine
Thanks!! I've managed to fix it using "int (T)(int)" declaration!!

Francesco
 
F

Francesco Montorsi

Hi,

SG ha scritto:
"isalpha" is not a type.
indeed :/
There are several possibilities:

template<int (&T)(int)> // T is a reference to a function
int foo() { // with *external* linkage.
return T(42);
}

int main() { foo<isalpha>(); }

But this way you can only use functions with the exact same signature
and only functions that have external linkage.
Thanks for the explanation! I think I'll go for this approach as the linkage is
not an issue for me.
You can also make T a
type for a function pointer (or function object) and pass the pointer
(or object) as additional parameter. This would be the "STL style":

template<typename T> // T is type (function pointer
int foo(T some_func) { // or function object)
return some_func(42);
}

int main() { foo(isalpha); } // function decays to pointer
Useful to know. Just out of curiosity: unless I'm wrong this second method
allows you to call functions also with internal linkage but they still need to
have the same exact signature as those of the function pointer type T, right?

Thanks!
Francesco
 
S

SG

SG ha scritto:> "isalpha" is not a type.

Useful to know. Just out of curiosity: unless I'm wrong this second method
allows you to call functions also with internal linkage but they still need to
have the same exact signature as those of the function pointer type T, right?

Yes. But T is a template parameter which can be deduced automatically.
T could be any function pointer type or function object type. You can
use any function (object) that makes the call expression in the
template well-formed -- for example a function object that takes a
double parameter:

struct Functor {
void operator()(double x) const;
};

template<typename T>
void foo(T func) {
int x=23;
func(c);
}

void bar() {
foo(Functor());
}

HTH,
SG
 
A

Alf P. Steinbach

* Francesco Montorsi:
I'm quite new to templates... I was asked to transform the following
macro

#define DECLARE_STRING_CHECK(func) \
inline bool func##String(const MyString& val) \
{ \
for ( MyString::const_iterator i = val.begin(); \
i != val.end(); \
++i ) \
if (func(*i) == 0) \
return false; \
return true; \
}

DECLARE_STRING_CHECK(isalpha) // declares isalphaString()
DECLARE_STRING_CHECK(isalnum)
DECLARE_STRING_CHECK(isdigit)

in a template.

Assuming 'isalpha' etc. are the C library functions: this code has generally
Undefined Behavior, that is, it's Wrong(TM).

The code has well-defined result only when compiled with an option to make
'char' an unsigned type, and/or is operating under a restriction to ASCII.

The practical result is that it may/will exhibit false positives and may/will
crash in a debug build.

So, instead of

if( func(*i) == 0 )

use e.g.

typedef unsigned char UnsignedChar;

...

if( func( UnsignedChar( *i ) ) == 0 )


Cheers & hth.,

- Alf (uncanny ability to detect sheer Wrongness(TM))
 
F

Francesco Montorsi

Alf P. Steinbach ha scritto:
> ...
Assuming 'isalpha' etc. are the C library functions: this code has
generally Undefined Behavior, that is, it's Wrong(TM).

The code has well-defined result only when compiled with an option to
make 'char' an unsigned type, and/or is operating under a restriction to
ASCII.
Sorry - I forgot to say that *i indeed evaluates to unsigned char as the
iterator operator* has been overloaded...

Francesco
 
P

pasa

also be aware that isalpha and cousins can be macros instead of
functions! Then you must either force the function versions or
introduce a wrapper-set.
 
P

pasa

also be aware that isalpha and cousins can be
Not in C++.

I recall having problems in practice with g++, not sure whether it was
yet 2.9x or also with 3.4.
It took a while to nail down the root cause.
The use context was like find_if(..., isspace).

So it better be aware of possibility and workarounds to save time :)
 
J

James Kanze

I recall having problems in practice with g++, not sure whether it was
yet 2.9x or also with 3.4.
It took a while to nail down the root cause.
The use context was like find_if(..., isspace).

Attention. The problem there has nothing to do with macros.
The problem there is that find_if is a template, and isspace is
overloaded.
So it better be aware of possibility and workarounds to save
time :)

Except that even if isspace were a macro, it would be a function
macro, which would be ignored in something like the above.
 
P

pasa

Is isspace overloaded? How?

I tried this in Cameau Online:

#include <vector>
#include <algorithm>
#include <ctype.h>

void foo()
{
std::vector<char> v(10);
std::find_if(v.begin(), v.end(), isspace);
}
end it compiles clean. Also in MSVC2008.
I even tried to force it by adding
#include <locale>
using namespace std;

still compiles.
(If you meant that as the overload, in the originally mentioned case
locale was definitely not included)

[hmm, it would be so nice to have gcc online too... ]
 
J

James Kanze

Is isspace overloaded? How?
I tried this in Cameau Online:
#include <vector>
#include <algorithm>
#include <ctype.h>
void foo()
{
std::vector<char> v(10);
std::find_if(v.begin(), v.end(), isspace);
}
end it compiles clean. Also in MSVC2008. I even tried to
force it by adding
#include <locale>
using namespace std;
still compiles.

If you include <locale> and add "using namespace std", it's
guaranteed by the standard not to compile. And doesn't with g++
(but surprisingly does with Sun CC and VC++).

Without the "using namespace std", of course, you're guaranteed
not to see the functions in <locale>, regardless, so the
ambiguity is not present. You still get undefined behavior at
runtime, of course, but that's a different question.
(If you meant that as the overload, in the originally
mentioned case locale was definitely not included)

The standard explicitly allows C++ headers to include any other
header. It's fully legal for <vector> or <algorithm> to include
[hmm, it would be so nice to have gcc online too... ]

Given its price, there doesn't seem to be any reason not to have
a local copy. (That's actually almost true for Comeau. The
difference is that because Comeau is licenced software, I don't
have a right to install it on machines where I work.)
 
P

pasa

If you include said:
it's guaranteed by the standard not to compile. And doesn't with g++
(but surprisingly does with Sun CC and VC++).

Same with Cameau. I did some experiments, code:

#include <vector>
#include <algorithm>


bool pr(int) {return false;}
//bool pr(const char *) {return false;}
template<class T> bool pr(T) {return false;}

void fffff()
{
std::vector<int> v;
std::find_if(v.begin(), v.end(), pr);
}

compiles. If you play with commenting in/out different set of pr-s,
the behavios suggests that the template is NEVER considered for the
argument. You need to say pr<int> or something in the find_if. Even
forced instantiation of pr<int> does not make it picked up.

Not sure which item in the standard describes the behavior for the
case, but possibly gcc got it the wrong way and the other compilers
correctly.
[hmm, it would be so nice to have gcc online too... ]
Given its price, there doesn't seem to be any
reason not to have a local copy.

What I imagined was being able to select from many versions. Having a
single copy is certainly no problem, but keeping a few dozens to
experiment with some piece of code once in a while is a different
beast.
 
C

coal

[hmm, it would be so nice to have gcc online too... ]
Given its price, there doesn't seem to be any
reason not to have a local copy.

What I imagined was being able to select from many versions.  Having a
single copy is certainly no problem, but keeping a few dozens to
experiment with some piece of code once in a while is a different
beast.

Shalom

I'm skeptical gcc will be a good compiler much longer. If
it were rewritten in C++ and then put on line I'd be more
optimistic. I agree that attempting to manage multiple local
compilers at the same time is tough. You mention dozens, but
in my opinion, more than two is a challenge. Kind of like taking
three big dogs for a walk at the same time. The dogs get their
own ideas about what makes sense. We don't have multiple versions
of the C++ Middleware Writer online yet, but if the time comes,
making it happen is fairly easy.


Brian Wood
Ebenezer Enterprises
www.webEbenezer.net
 

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,780
Messages
2,569,611
Members
45,280
Latest member
BGBBrock56

Latest Threads

Top