Topic: pointer to function conversions


Author: Nikolay Mladenov <mladenovn@yesic.com>
Date: 1999/10/11
Raw View
Alain Miniussi wrote:

> The standard does not allow any conversion betwen pointer
> to function, even conversion that seems to be perfectly
> safe (void (*)(T*) -> void (*)(T const*) for example. Why ?
>
> Alain

Can we consider this:

class Button
{
public:
    const string &caption() const;
    void caption(const string&);
    void (* onClick)(Button *);
    void Click()
    {
        if(onClick)
            onClick(this);
    }
};

This all is kind of very natural, right?

then:

setCaption(Button *btn)
{
    btn->caption("setCaption");
}

void printCaption(const Button *btn)
{
        std::cout<<btn->Caption()<<std::endl;
}


int main()
{
    Button btn;
    btn.onClick = setCaption; // is legal
    btn.onClick = printCaption// not legal, but safe
}

If we write:

inline void printCaption1(Button *btn)
{
    printCaption(btn);
}

btn.onCaption = printCaption1; //it's OK

And now come the questions:

1. Is there a compiler which will generate (with optimization ON) code for
    printCaption1(btn);
different than
    printCaption(btn);

2. If  no, than the conversion from void(*)(const Button*) to void
(*)(Button*) is almost standard
    if yes:), who's buying it:)

Nickolay




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/10/09
Raw View
Ron Natalie wrote:

> By arguing that certain function conversions are allowed, you are arguing
> that certain types are compatible without the benefit of the compiler
> converting them.

The point is to make these types implicitly convertible.

> All others, including pointer to
> pointer-to-const conversions involve some intervention (even if it is
> just handwaving) by the compiler to convert them.

All the cv-conversions, including const_cast, are just
hand-waving. The point is to make A1 (*) (B1) convertible
to A2 (*) (B2) iff A1 is convertible to A2, B2 is convertible
to B1, and these conversions only involve hand-waving.

Trivial to implement on every existing compiler.
Low probability of breaking code.

(No, I don't consider it sane to implement A1 (*) (B1)
and A2 (*) (B2) differently.)

> While it might be
> true, that some types don't need any conversion,

I assume that you mean that some type only need
hand-waving.

> it would be a mess
> to try to enumerate them in the standard,

???

> this abuse of C++'s otherwise strong typing.

???

--

Valentin Bonnard
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: 1999/10/10
Raw View
Alain Miniussi wrote:
>
> AllanW wrote:
> >
> > In article <37FBB24F.F188F97@sophia.cnrs.fr>,
> >   Alain Miniussi <alain@sophia.cnrs.fr> wrote:
> > > The standard does not allow any conversion betwen pointer
> > > to function, even conversion that seems to be perfectly
> > > safe (void (*)(T*) -> void (*)(T const*) for example. Why ?
> >
> > I won't attempt to argue why *NO* conversions are allowed (is
> > that true?).
>
> Yes, chapter 4 (standard conversion) enumerate the standard
> conversion, the only conversion allowed concerning function
> is the one that convert un function in its conresponding
> function type.

That got a little garbled. The exact words from section 4 are:
'An lvalue of function type T can be converted to an rvalue of type
"pointer to T."'

However, in section 5.2.10 p6, it says that using reinterpret_cast<>,

'A pointer to a function can be explicitly converted to a pointer to a
function of a different type. The effect of calling a function through a
pointer to a function type (8.3.5) that is not the same as the type used
in the definition of the function is undefined. ... converting an rvalue
of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are
function types) and back to its original type yields the original
pointer value ..."

Thus, it is legal to convert between pointer-to-function types, and even
potentially useful, but you must convert it back to the true type before
dereferencing it. This means you must have some way of keeping track of
the true type of the converted pointer. Most of the good examples I
could give are really C code. They could be re-designed more cleanly by
using C++ templates with pointer-to-function template type parameters,
or overloading functions with pointer-to-function parameter types. That
isn't necessarily an option, though, with legacy code or third-party
libraries.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/10/08
Raw View
Alain Miniussi wrote:

> The standard does not allow any conversion betwen pointer
> to function, even conversion that seems to be perfectly
> safe (void (*)(T*) -> void (*)(T const*) for example. Why ?

For the tenth time: because use of any such converted value
yields undefined behaviour (see the standard, the ARM).

And don't ask me why use of converted value should yield
undefined behaviour (but you can still read the relevant
passage in the ARM, which says that it's ``natural'' (sic)
to implement parameter passing differently for T* and
const T*).

--

Valentin Bonnard
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/10/08
Raw View
Steve Clamage wrote:

> You could invent combinations where it is unlikely that you would
> run into a problem,

No. With covariance and contravariance w/o change of
representation it's _impossible_ to run into problems
on every existing, and resonnable, implementation.

(The actual answer to the original question is 42.)

--

Valentin Bonnard
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/10/08
Raw View
AllanW wrote:

> If the conversion from void(*)(char*) to void(*)(const char*)
> were legal,

He obviously meant the contrary.

He wants ret1 (*) (arg1) to be convertible to
ret2 (*) (arg2) if ret1 is convertible to ret2
and arg2 is convertible to arg1, with no
reprensentation change.

As to why it is not allowed, I would reply 42.

--

Valentin Bonnard


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Ron Natalie <ron@sensor.com>
Date: 1999/10/08
Raw View


AllanW wrote:

> I won't attempt to argue why *NO* conversions are allowed (is
> that true?). But, for your "perfectly safe" example:
>

By arguing that certain function conversions are allowed, you are arguing
that certain types are compatible without the benefit of the compiler
converting them.  The only one that I can thing of along those lines
is layout compatible POD structures.  All others, including pointer to
pointer-to-const conversions involve some intervention (even if it is
just handwaving) by the compiler to convert them.  While it might be
true, that some types don't need any conversion, it would be a mess
to try to enumerate them in the standard, and there really doesn't
seem to be any overriding reason to allow this abuse of C++'s otherwise
strong typing.

Someday somebody is going to make an implementation where the linkage
of int and void function returns are different and we're finally going
to see who's been paying attention to the language definition :-)



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Alain Miniussi <alain@sophia.cnrs.fr>
Date: 1999/10/09
Raw View
AllanW wrote:
>
> In article <37FBB24F.F188F97@sophia.cnrs.fr>,
>   Alain Miniussi <alain@sophia.cnrs.fr> wrote:
> > The standard does not allow any conversion betwen pointer
> > to function, even conversion that seems to be perfectly
> > safe (void (*)(T*) -> void (*)(T const*) for example. Why ?
>
> I won't attempt to argue why *NO* conversions are allowed (is
> that true?).

Yes, chapter 4 (standard conversion) enumerate the standard
conversion, the only conversion allowed concerning function
is the one that convert un function in its conresponding
function type.

> But, for your "perfectly safe" example:

No, "_seems to be_ perfectly safe".

>     void showstring(const char*x)
>       { std::cout << "Debug: Value is " << x << std::endl; }
>     void (*ptrShow)(const char*) = showstring;
>
>     void changestring(char*x) { ++x[0]; }
>     void (*ptrChange)(char*) = changestring;
>
>     void do_stuff(void(*foo)(const char*), const char*x) {
>        std::cout << "Before: " << x << std::endl;
>        foo(x); // This should have no effect!
>        std::cout << "After: " << x << std::endl;
>     }
>
>     const char buff[] = "Abc";
>
>     int main(int,char*[]) {
>        // This call is perfectly legal
>        do_stuff(ptrShow, buff);
>
>        // This one attempts to convert ptrChange, which is
>        // type void(*)(char*), to type void(*)(const char*)
>        do_stuff(ptrChange, buff); // ILLEGAL
>     }
>
> If the conversion from void(*)(char*) to void(*)(const char*)
> were legal, then the line marked ILLEGAL would not only be
> error free, but it wouldn't even deserve a warning. And yet
> function changeString would attempt to modify the const
> string in buff[].

Thanks ! I did suspect that there was something similar to
T const** -> T**
but could not find it.

Alain
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Alain Miniussi <alain@sophia.cnrs.fr>
Date: 1999/10/09
Raw View
Steve Clamage wrote:
>
> [...]
> You could invent combinations where it is unlikely that you would
> run into a problem, but the standard does not attempt to
> enumerate them. It just says the results are undefined, meaning
> that an implementation is allowed to document the conditions
> under which conversions are safe.

By the way, the one I mentionned is unsafe (as proved by Allan)
(and most of the other standard conversions are likely to imply
more complex conversion).

Thanks,

Alain
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Alain Miniussi <alain@sophia.cnrs.fr>
Date: 1999/10/09
Raw View
Valentin Bonnard wrote:
>
> Alain Miniussi wrote:
>
> > The standard does not allow any conversion betwen pointer
> > to function, even conversion that seems to be perfectly
> > safe (void (*)(T*) -> void (*)(T const*) for example. Why ?
>
> For the tenth time: because use of any such converted value
> yields undefined behaviour (see the standard, the ARM).

Yes, this point is mentionned in my question, but...

> And don't ask me why use of converted value should yield
> undefined behaviour

...so, forget it.

>(but you can still read the relevant
>passage in the ARM, which says that it's ``natural'' (sic)
>to implement parameter passing differently for T* and
>const T*).

Where exactly in the ARM ? I was not to find it in the "natural"
place (and my full reading of the ARM is 5 years old now).

Alain
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/10/09
Raw View
Valentin Bonnard <Bonnard.V@wanadoo.fr> writes:

>Steve Clamage wrote:

>> You could invent combinations where it is unlikely that you would
>> run into a problem,

>No. With covariance and contravariance w/o change of
>representation it's _impossible_ to run into problems
>on every existing, and resonnable, implementation.

I suppose you mean the specific case where all corresponding
function parameters and the return types are either compatible or
are data pointers.

The original question was not so limiting.

I hope you will agree that casting between, say,
myStruct(*)(myStruct)  and  int(*)(int)  and then trying to
call the function is unlikely to work.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Alain Miniussi <alain@sophia.cnrs.fr>
Date: 1999/10/07
Raw View
The standard does not allow any conversion betwen pointer
to function, even conversion that seems to be perfectly
safe (void (*)(T*) -> void (*)(T const*) for example. Why ?

Alain
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Ron Natalie <ron@sensor.com>
Date: 1999/10/07
Raw View


Alain Miniussi wrote:
>
> The standard does not allow any conversion betwen pointer
> to function, even conversion that seems to be perfectly
> safe (void (*)(T*) -> void (*)(T const*) for example. Why ?
>
What makes you think that such a conversion is safe?  Actually,
the standard does allow reintrepret_cast here, but unless you
cast back to the original pointer to function type, the usage
is undefined.

There's nothing in the standard that precludes the subroutine
linkage for T* arguments from being different from const T*.
The onus is on the calling code to convert things and pass
them as appropriate to the function declaration.



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Alain Miniussi <alain@sophia.cnrs.fr>
Date: 1999/10/07
Raw View
Ron Natalie wrote:
>
> Alain Miniussi wrote:
> >
> > The standard does not allow any conversion betwen pointer
> > to function, even conversion that seems to be perfectly
> > safe (void (*)(T*) -> void (*)(T const*) for example. Why ?
> >
> What makes you think that such a conversion is safe?

I tried it and it didn't crash my disk :-) I know it's not
a valid argument, but some compilers allows it, it seems to
works and I did not find any abvious reason (but I didn't
look closely) why these two kind of pointers should be
considered differently as far as argument passing is concern.
One reason to prohibit such a conversion would be that there
is actualy a possibility for a diference so....

>  Actually,
> the standard does allow reintrepret_cast here, but unless you
> cast back to the original pointer to function type, the usage
> is undefined.

Yes, the quetion was "why" (42 is not a valid answer)

> There's nothing in the standard that precludes the subroutine
> linkage for T* arguments from being different from const T*.
> The onus is on the calling code to convert things and pass
> them as appropriate to the function declaration.

Yes,  it seems obvious for most standard conversion, but is
it true for T * and T const * ? does anyone know of a compiler
that does not consider these two pointer in the same way (for
this issue) or doe anyone see a context where it would be usefull ?
(on the opposite, can someone argue that these two kind of pointer
have no reason to be considered differently).

And by the way, is it the reason why it is prohibited ? (I can think
of other reason to prohibit such a conversion).

Alain


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Alain Miniussi <alain@sophia.cnrs.fr>
Date: 1999/10/07
Raw View
Ron Natalie wrote:
>
> Alain Miniussi wrote:
> >
> > Yes,  it seems obvious for most standard conversion, but is
> > it true for T * and T const * ? does anyone know of a compiler
> > that does not consider these two pointer in the same way (for
> > this issue) or doe anyone see a context where it would be usefull ?
> > (on the opposite, can someone argue that these two kind of pointer
> > have no reason to be considered differently).
> >
> > And by the way, is it the reason why it is prohibited ? (I can think
> > of other reason to prohibit such a conversion).
>
> Most likely because there wasn't any good reason to allow it and
> enumerating a bunch of cases which allow you to mismatch function
> definitions wasn't thought to be worth the effort.

Yes, and there are user defined conversion, if someone provide a
a void (*)(T *) function that is called through void (*)(T const*)
on some object prividing both conversions.... also, a function
using a T* is more likefly to delete its argument than if its
a T const* (well, these would be 2 example of poorly written code
but...)

> While I can't think of any direct reason why const T* and T* would
> be encoded different, imagine an architecture that put a bit in a
> pointer to make it read only...

I don't think this specific case would be an issue, const T* only says
the pointed object (that can be otherwise declared const or not) can't
be modified through this particular pointer (and informations on this
particular pointer are known at compile time).

Alain


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/10/08
Raw View
Alain Miniussi <alain@sophia.cnrs.fr> writes:

>Ron Natalie wrote:
>>
>> Alain Miniussi wrote:
>> >
>>  Actually,
>> the standard does allow reintrepret_cast here, but unless you
>> cast back to the original pointer to function type, the usage
>> is undefined.

>Yes, the quetion was "why" (42 is not a valid answer)

If you convert a function pointer to one of a different type,
what could you expect to do with it? If you try to call the
function via the different pointer type, you violate the
compiler's expectations of how the function is called.
That's why the conversion is not implicit, and why the
results are undefined.

You could invent combinations where it is unlikely that you would
run into a problem, but the standard does not attempt to
enumerate them. It just says the results are undefined, meaning
that an implementation is allowed to document the conditions
under which conversions are safe.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW <allan_w@my-deja.com>
Date: 1999/10/08
Raw View
In article <37FBB24F.F188F97@sophia.cnrs.fr>,
  Alain Miniussi <alain@sophia.cnrs.fr> wrote:
> The standard does not allow any conversion betwen pointer
> to function, even conversion that seems to be perfectly
> safe (void (*)(T*) -> void (*)(T const*) for example. Why ?

I won't attempt to argue why *NO* conversions are allowed (is
that true?). But, for your "perfectly safe" example:

    void showstring(const char*x)
      { std::cout << "Debug: Value is " << x << std::endl; }
    void (*ptrShow)(const char*) = showstring;

    void changestring(char*x) { ++x[0]; }
    void (*ptrChange)(char*) = changestring;

    void do_stuff(void(*foo)(const char*), const char*x) {
       std::cout << "Before: " << x << std::endl;
       foo(x); // This should have no effect!
       std::cout << "After: " << x << std::endl;
    }

    const char buff[] = "Abc";

    int main(int,char*[]) {
       // This call is perfectly legal
       do_stuff(ptrShow, buff);

       // This one attempts to convert ptrChange, which is
       // type void(*)(char*), to type void(*)(const char*)
       do_stuff(ptrChange, buff); // ILLEGAL
    }

If the conversion from void(*)(char*) to void(*)(const char*)
were legal, then the line marked ILLEGAL would not only be
error free, but it wouldn't even deserve a warning. And yet
function changeString would attempt to modify the const
string in buff[].

--
Allan_W@my-deja.com is a "Spam Magnet," never read.
Please reply in newsgroups only, sorry.


Sent via Deja.com http://www.deja.com/
Before you buy.


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]