Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

templated function help

0 views
Skip to first unread message

Francesco Montorsi

unread,
Jan 31, 2009, 1:45:45 PM1/31/09
to
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


Daniel Pitts

unread,
Jan 31, 2009, 2:09:38 PM1/31/09
to
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

--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

SG

unread,
Jan 31, 2009, 2:19:00 PM1/31/09
to
On 31 Jan., 19:45, Francesco Montorsi <f...@hotmail.com> wrote:
> 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

Francesco Montorsi

unread,
Jan 31, 2009, 4:02:20 PM1/31/09
to
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

Francesco Montorsi

unread,
Jan 31, 2009, 4:05:17 PM1/31/09
to
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

SG

unread,
Jan 31, 2009, 5:24:26 PM1/31/09
to
On 31 Jan., 22:05, Francesco Montorsi <f...@hotmail.com> wrote:
> SG ha scritto:> "isalpha" is not a type.
> > 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?

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

Alf P. Steinbach

unread,
Jan 31, 2009, 8:00:46 PM1/31/09
to
* 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))

Francesco Montorsi

unread,
Feb 1, 2009, 8:42:06 AM2/1/09
to
Alf P. Steinbach ha scritto:
>> if (func(*i) == 0) \
> ...

> 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

pa...@lib.hu

unread,
Feb 1, 2009, 12:42:02 PM2/1/09
to
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.

Pete Becker

unread,
Feb 1, 2009, 12:49:15 PM2/1/09
to
On 2009-02-01 12:42:02 -0500, pa...@lib.hu said:

> also be aware that isalpha and cousins can be macros instead of
> functions!

Not in C++.

> Then you must either force the function versions or
> introduce a wrapper-set.

And even if they are macros, in this context the macro wouldn't be
used. If the first non-whitespace character after the use of a name
that's the name of a function-like macro is not a left parenthesis the
macro isn't applied.

int transform(int);
#define transform(x) x // silly transformation

template <int (*)(int)> void f();

f<transform>(); // transform refers to the function, not the macro

That's also the reason that the usual formula for forcing the function
works: in (transform), transform names the function, because the first
non-whitespace character that follows it is ')', not '('.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

pa...@lib.hu

unread,
Feb 2, 2009, 8:02:44 AM2/2/09
to
>> also be aware that isalpha and cousins can be
>> macros instead of functions!
>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 :)

James Kanze

unread,
Feb 3, 2009, 4:15:22 AM2/3/09
to
On Feb 2, 2:02 pm, p...@lib.hu wrote:
> >> also be aware that isalpha and cousins can be
> >> macros instead of functions!
> >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).

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.

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

pa...@lib.hu

unread,
Feb 3, 2009, 10:40:56 PM2/3/09
to
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... ]


James Kanze

unread,
Feb 4, 2009, 5:42:19 AM2/4/09
to
On Feb 4, 4:40 am, p...@lib.hu wrote:
> 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
<locale>. (It would be fully legal for an implementation to
just have a single, precompiled header, with everything in it.)

> [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.)

pa...@lib.hu

unread,
Feb 7, 2009, 11:56:25 AM2/7/09
to
>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++).

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.

co...@mailvault.com

unread,
Feb 8, 2009, 3:23:06 AM2/8/09
to
On Feb 7, 10:56 am, p...@lib.hu wrote:
> >> [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

0 new messages