Topic: C" linkage functions and template arguments


Author: kanze@gabi-soft.de (James Kanze)
Date: Thu, 28 Nov 2002 20:04:12 +0000 (UTC)
Raw View
dnc@ccieurope.com (Dan Noedskouv Christensen) wrote in message
news:<l7lm3fjs95.fsf@localhost.localdomain>...

> I have a small problem regarding linkage of function types, used as
> template arguments.  The following example displays the problem:

>    #include <cctype> // defines toupper
>    #include <algorithm>
>    #include <string>

>    using namespace std;

>    int main()
>    {
>       string aText = "This is a text.";
>       transform(aText.begin(), aText.end(), aText.begin(), toupper);
>    }

> This works fine with several compilers, but one compiler complains
> about toupper() having C linkage.

Whether the transform compiles is undefined, but not for any reasons of
linkage.

> Is it the latter compiler that is wrong, or are there limitations on
> the linkage of function types in templates?

None that I know of.  The linkage is part of the type, but I don't know
of any rule forbidding the instantiation of a template over a type with
C linkage.

> I tried to decipher the standard, but I'm not that fluent in the
> standardeese language and couldn't find any section that seemed to
> imply such a restriction. I might be naive, but I would have thought
> that different language linkages where simply treated as different
> types in this regard.

They should be.

> Explicitly casting the toupper function to have C++ language linkage
> using reinterpret_cast, happens to solve the problem, but I would like
> to know if the above example is supposed to be well formed, or if I'm
> wading in implementation defined/undefined behaviour?

The explicit cast is an invitation to problems, and introduces undefined
behavior.  It certainly isn't portable.

There is a problem however.  In order to instantiate the template, the
compiler must be able to induce the type(s).  For transform, one of the
types is the type of the last parameter.  And in the standard, there are
an infinity of toupper functions, all but one defined in <locale>.  You
don't include <locale>, but any of the other headers might; if one does,
your code won't compile, because the compiler won't be able to deduce
the type of toupper.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dnc@ccieurope.com (Dan Noedskouv Christensen)
Date: Fri, 29 Nov 2002 14:58:19 +0000 (UTC)
Raw View
kanze@gabi-soft.de (James Kanze) writes:

> dnc@ccieurope.com (Dan Noedskouv Christensen) wrote in message
> news:<l7lm3fjs95.fsf@localhost.localdomain>...
>
> > Explicitly casting the toupper function to have C++ language linkage
> > using reinterpret_cast, happens to solve the problem, but I would like
> > to know if the above example is supposed to be well formed, or if I'm
> > wading in implementation defined/undefined behaviour?
>
> The explicit cast is an invitation to problems, and introduces undefined
> behavior.  It certainly isn't portable.

I know, and I am taking a different approach in the production
code. But it shows that it (most likely) is the linkage that caused
problems on said compiler.

> There is a problem however.  In order to instantiate the template, the
> compiler must be able to induce the type(s).  For transform, one of the
> types is the type of the last parameter.  And in the standard, there are
> an infinity of toupper functions, all but one defined in <locale>.  You
> don't include <locale>, but any of the other headers might; if one does,
> your code won't compile, because the compiler won't be able to deduce
> the type of toupper.

Thanks, I didn't think of that.

This can't even be resolved (portably) by explicitly stating the types
in the call of transform, as 17.4.2.2p2 says it is undefined if the
linkage of C library functions are "C" or "C++". :-(

Thanks for the help,
Dan

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: spambo_steffan_lankinensucks@hotmail.com ("Bo-Staffan Lankinen")
Date: Sun, 1 Dec 2002 18:34:11 +0000 (UTC)
Raw View
> Is it the latter compiler that is wrong, or are there limitations on
> the linkage of function types in templates?

The latter compiler is correct.

> I tried to decipher the standard, but I'm not that fluent in the
> standardeese language and couldn't find any section that seemed to
> imply such a restriction. I might be naive, but I would have thought
> that different language linkages where simply treated as different
> types in this regard.

According to 7.5/1: Two function types with different language linkages are
distinct types even if they are otherwise identical.

> Explicitly casting the toupper function to have C++ language linkage
> using reinterpret_cast, happens to solve the problem, but I would like
> to know if the above example is supposed to be well formed, or if I'm
> wading in implementation defined/undefined behaviour?

It's undefined behavior. A better way of solving this problem is to create a
wrapper function with the correct linkage that invokes the function.

Bo-Staffan


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@integrable-solutions.net (Gabriel Dos Reis)
Date: Sun, 1 Dec 2002 18:39:22 +0000 (UTC)
Raw View
kanze@gabi-soft.de (James Kanze) writes:

[...]

| > Is it the latter compiler that is wrong, or are there limitations on
| > the linkage of function types in templates?
|
| None that I know of.  The linkage is part of the type,

This is untrue: linkage is part of the name attributes.

[...]

| There is a problem however.  In order to instantiate the template, the
| compiler must be able to induce the type(s).  For transform, one of the
| types is the type of the last parameter.  And in the standard, there are
| an infinity of toupper functions, all but one defined in <locale>.  You
| don't include <locale>, but any of the other headers might; if one does,
| your code won't compile, because the compiler won't be able to deduce
| the type of toupper.

This is exactly what we told the OP when he submitted the PR.

--
Gabriel Dos Reis,       gdr@integrable-solutions.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net ("James Kuyper Jr.")
Date: Mon, 2 Dec 2002 07:06:13 +0000 (UTC)
Raw View
Gabriel Dos Reis wrote:
> kanze@gabi-soft.de (James Kanze) writes:
>
> [...]
>
> | > Is it the latter compiler that is wrong, or are there limitations on
> | > the linkage of function types in templates?
> |
> | None that I know of.  The linkage is part of the type,
>
> This is untrue: linkage is part of the name attributes.

Language linkage applies to both types and to names.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: fjh@students.cs.mu.OZ.AU (Fergus Henderson)
Date: Mon, 2 Dec 2002 08:23:01 +0000 (UTC)
Raw View
gdr@integrable-solutions.net (Gabriel Dos Reis) writes:

>kanze@gabi-soft.de (James Kanze) writes:
>
>[...]
>
>| > Is it the latter compiler that is wrong, or are there limitations on
>| > the linkage of function types in templates?
>|
>| None that I know of.  The linkage is part of the type,
>
>This is untrue: linkage is part of the name attributes.

James Kanze is right: C++98 section 7.5 paragraph 1 says
"All function types [...] have a language linkage."

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: Mon, 2 Dec 2002 16:32:45 +0000 (UTC)
Raw View
dnc@ccieurope.com (Dan Noedskouv Christensen) wrote in message
news:<l74ra0wq5p.fsf@localhost.localdomain>...
> kanze@gabi-soft.de (James Kanze) writes:

> > dnc@ccieurope.com (Dan Noedskouv Christensen) wrote in message
> > news:<l7lm3fjs95.fsf@localhost.localdomain>...

> > > Explicitly casting the toupper function to have C++ language
> > > linkage using reinterpret_cast, happens to solve the problem, but
> > > I would like to know if the above example is supposed to be well
> > > formed, or if I'm wading in implementation defined/undefined
> > > behaviour?

> > The explicit cast is an invitation to problems, and introduces
> > undefined behavior. It certainly isn't portable.

> I know, and I am taking a different approach in the production code.
> But it shows that it (most likely) is the linkage that caused problems
> on said compiler.

Not necessarily.

> > There is a problem however. In order to instantiate the template,
> > the compiler must be able to induce the type(s). For transform, one
> > of the types is the type of the last parameter. And in the standard,
> > there are an infinity of toupper functions, all but one defined in
> > <locale>. You don't include <locale>, but any of the other headers
> > might; if one does, your code won't compile, because the compiler
> > won't be able to deduce the type of toupper.

> Thanks, I didn't think of that.

And that is what could be causing the problem.  The simple name toupper
could have an infinity of different types; the results of a cast
(reinterpret_cast or other) has exactly one type.  And if the compiler
knows the type, it can instantiate the function.

The "standard" solution is to use a (safe) static_cast:

    std::transform( ... , static_cast< int (*)(int) >( toupper ) ) ;

The possibility of an extern "C" in this case is a bit of a problem.
According to the standard: "Two function types with different language
linkages are distinct types even if they are otherwise identical" -- the
linkage is explicitly part of the type.  And as far as I can tell, a
static_cast cannot be used to change the type of a pointer to a
function.  (This is logical, since changing the type of a pointer to a
function is potentially very dangerous -- calling a function with "C"
linkage as if it had "C++" linkage is undefined behavior, and will cause
crashes and other strange behavior on some systems.)

This means that in the static_cast, you must give the correct linkage.
Except that you don't know the correct linkage; it is explicitly
implementation dependant whether the linkage is "C" or "C++".  (I don't
think that you can specify the linkage directly in the static_cast, but
you can use extern "C" on a typedef, and use the typedef'ed name in the
static_cast.)

> This can't even be resolved (portably) by explicitly stating the types
> in the call of transform, as 17.4.2.2p2 says it is undefined if the
> linkage of C library functions are "C" or "C++". :-(

Right.

Of course, it is also undefined behavior to pass a char to the "C"
version of toupper (which requires an int in the range [0...UCHAR_MAX]
or -1), so you probably don't want to do this anyway.

Something along the lines of:

    std::bind2nd(
        std::ptr_fun(
            static_cast< bool (*)( char, locale const& ) >( std::toupper ),
        std::locale() ) )

should do the trick, supposing I've not missed something.  (It's also
great for showing off in front of the collegues, and given the
readability, it's probably pretty good job security as well, if they
actually let you get away with it.)

Personally, the one time I had to do something along these lines, I
knocked out a templated functor class over std::ctype_base::mask.  From
memory:

    template< std::ctype_base::mask m >
    class Is
    {
    public:
        Is( locale const& l )
            : myCType( &std::use_facet< ctype< char > >( l ) ) {}
        bool operator()( char ch ) const
        {
            return myCType->is( m, ch ) ;
        }
    private:
        std::ctype< char > const* myCType ;
    } ;

(The use of a pointer instead of a reference for the member variable is
to allow assignment.)

Something like this allows writing:

    std::transform( v.begin(), v.end(), v.begin(),
                    Is< std::ctype_base::isupper >( locale() ) ) ;

IMHO, the code at the call site is more readable than the version with
the binders, and the template class itself can be made reasonably
readable with a few comments.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@integrable-solutions.net (Gabriel Dos Reis)
Date: Mon, 2 Dec 2002 16:32:50 +0000 (UTC)
Raw View
fjh@students.cs.mu.OZ.AU (Fergus Henderson) writes:

| gdr@integrable-solutions.net (Gabriel Dos Reis) writes:
|
| >kanze@gabi-soft.de (James Kanze) writes:
| >
| >[...]
| >
| >| > Is it the latter compiler that is wrong, or are there limitations on
| >| > the linkage of function types in templates?
| >|
| >| None that I know of.  The linkage is part of the type,
| >
| >This is untrue: linkage is part of the name attributes.
|
| James Kanze is right: C++98 section 7.5 paragraph 1 says
| "All function types [...] have a language linkage."

Gloops.  You're right.  And James Kanze is right.  Sorry for the
confusion.

--
Gabriel Dos Reis,       gdr@integrable-solutions.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: Tue, 3 Dec 2002 14:21:19 +0000 (UTC)
Raw View
kanze@gabi-soft.de (James Kanze) wrote in message
news:<d6651fb6.0212020349.695b1e42@posting.google.com>...

    [Following up to my own post...]
> dnc@ccieurope.com (Dan Noedskouv Christensen) wrote in message
> news:<l74ra0wq5p.fsf@localhost.localdomain>...

    [...]

> Personally, the one time I had to do something along these lines, I
> knocked out a templated functor class over std::ctype_base::mask. From
> memory:

>     template< std::ctype_base::mask m >
>     class Is
>     {
>     public:
>         Is( locale const& l )
>             : myCType( &std::use_facet< ctype< char > >( l ) ) {}
>         bool operator()( char ch ) const
>         {
>             return myCType->is( m, ch ) ;
>         }
>     private:
>         std::ctype< char > const* myCType ;
>     } ;

> (The use of a pointer instead of a reference for the member variable
> is to allow assignment.)

> Something like this allows writing:

>     std::transform( v.begin(), v.end(), v.begin(),
>                     Is< std::ctype_base::isupper >( locale() ) ) ;

> IMHO, the code at the call site is more readable than the version with
> the binders, and the template class itself can be made reasonably
> readable with a few comments.

As the reader will no doubt have noticed, when I had to do something
like this, the algorithm in question was find, and not transform:-).

In practice, std::transform is useless with text, or at least, human
language text.  Almost any transformation you can think of will not
necessarily result in the same number of characters as you started out
with: toupper( '   ' ), for example, should return the string "SS".  About
the only thing I've found in the standard which might be potentially
useful here is std::collate::transform.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: usenet@phatbasset.com ("Hillel Y. Sims")
Date: Wed, 4 Dec 2002 05:36:48 +0000 (UTC)
Raw View
"James Kanze" <kanze@gabi-soft.de> wrote in message
news:d6651fb6.0212030244.6068a149@posting.google.com...
> In practice, std::transform is useless with text, or at least, human
> language text.  Almost any transformation you can think of will not
> necessarily result in the same number of characters as you started out
> with: toupper( '=DF' ), for example, should return the string "SS".  Ab=
out
> the only thing I've found in the standard which might be potentially
> useful here is std::collate::transform.
>

Works great for English text. ;-) But you are obviously correct w/r/t
generic language support; Scott Meyers wrote an appendix discussing this
exact issue (and a generic algorithm to implement a solution) in _Effecti=
ve
STL_.

hys

--
(c) 2002 Hillel Y. Sims
FactSet Research Systems
hsims AT factset.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dnc@ccieurope.com (Dan Noedskouv Christensen)
Date: Wed, 27 Nov 2002 17:49:11 +0000 (UTC)
Raw View
Hi!

I have a small problem regarding linkage of function types, used as
template arguments.  The following example displays the problem:

   #include <cctype> // defines toupper
   #include <algorithm>
   #include <string>

   using namespace std;

   int main()
   {
      string aText = "This is a text.";
      transform(aText.begin(), aText.end(), aText.begin(), toupper);
   }

This works fine with several compilers, but one compiler complains
about toupper() having C linkage.

Is it the latter compiler that is wrong, or are there limitations on
the linkage of function types in templates?

I tried to decipher the standard, but I'm not that fluent in the
standardeese language and couldn't find any section that seemed to
imply such a restriction. I might be naive, but I would have thought
that different language linkages where simply treated as different
types in this regard.

Explicitly casting the toupper function to have C++ language linkage
using reinterpret_cast, happens to solve the problem, but I would like
to know if the above example is supposed to be well formed, or if I'm
wading in implementation defined/undefined behaviour?

Thanks,
Dan N. Christensen

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]