function pointes and templates

J

John Harrison

Can anyone explain why this code fails to compile?

#include <iostream>

void func()
{
std::cout << "success!\n";
}

struct S
{
template <class F>
void method(const F& f)
{
f();
}
};

int main()
{
S s;
s.method(func);
}

but with a very slight change to main

int main()
{
S s;
s.method(&func); // change here
}

it compiles and works.

john
 
B

Buster

John said:
Can anyone explain why this code fails to compile?

#include <iostream>

void func()
{
std::cout << "success!\n";
}

struct S
{
template <class F>
void method(const F& f)
{
f();
}
};

int main()
{
S s;
s.method(func);
}

but with a very slight change to main

int main()
{
S s;
s.method(&func); // change here
}

it compiles and works.

john

I think it's because a function (not being an object) cannot be const,
as illustrated by this, which does compile on my system:

void f () { }

int main ()
{
typedef void (& func_t) ();

const func_t f = func;
func_t g = f; // If g's referent were really const this wouldn't work.
}

Therefore, you can't initialize a reference-to-const-T with a function,
since a function can be T but not const T.

The same is not true of a pointer-to-function.
 
R

Rob Williscroft

John Harrison wrote in
Can anyone explain why this code fails to compile?

#include <iostream>

void func()
{
std::cout << "success!\n";
}

struct S
{
template <class F>
void method(const F& f)
{
f();
}
};

int main()
{
S s;
s.method(func);

Both of these are ok:

s.method( static_cast< void (*)() >( func ) );
s.method( static_cast< void (&)() >( func ) );

Both conversion's are standard conversions and have equal rank (*).
Both require a futher qualification adjustment (add const).

*) Exact Match.

}

but with a very slight change to main

int main()
{
S s;
s.method(&func); // change here
}

it compiles and works.

There is no ambiguity, &func is a function pointer, only a
futher qaulification adjustment is required. There is no
ambiguos conversion to reference-to-function available.

This is why functors are generaly passed by value.

Rob.
 
T

tom_usenet

Both of these are ok:

s.method( static_cast< void (*)() >( func ) );
s.method( static_cast< void (&)() >( func ) );

Both conversion's are standard conversions and have equal rank (*).
Both require a futher qualification adjustment (add const).

*) Exact Match.

Yes, but 14.8.2.1/2 says that during template argument deduction, if
the argument is a function type, it is replaced with the function
pointer type, so there is no possibility of your second version above
being deduced. This is a template argument deduction issue, not
overloading - there is only one function called func and one called
method.
There is no ambiguity, &func is a function pointer, only a
futher qaulification adjustment is required. There is no
ambiguos conversion to reference-to-function available.

This is why functors are generaly passed by value.

There is no ambiguity anyway - Comeau and GCC compile the original
code fine, without the &.

Tom
 
R

Rob Williscroft

tom_usenet wrote in
Yes, but 14.8.2.1/2 says that during template argument deduction, if
the argument is a function type, it is replaced with the function
pointer type, so there is no possibility of your second version above
being deduced. This is a template argument deduction issue, not
overloading - there is only one function called func and one called
method.

1 Template argument deduction is done by comparing each function
template parameter type (call it P) with the type of the
corresponding argument of the call (call it A) as described below.

2 If P is not a reference type:

...

— If A is a function type, the pointer type produced by the
function-to-pointer standard conversion (4.3) is used in
place of A for type deduction; otherwise,

...

I quoted (1) as it describes P.

Given:

struct S
{
template <class F>
void method(const F& f)
{
f();
}
};

You seem to think "template parameter type (call it P)" is F where as
I think it is F const &.

Rob.
 
T

tom_usenet

tom_usenet wrote in

1 Template argument deduction is done by comparing each function
template parameter type (call it P) with the type of the
corresponding argument of the call (call it A) as described below.

2 If P is not a reference type:

Oops, I missed the "If P is not a reference type". In this case, P is
a reference type of course, so the paragraph below doesn't apply.
...

— If A is a function type, the pointer type produced by the
function-to-pointer standard conversion (4.3) is used in
place of A for type deduction; otherwise,

...

I quoted (1) as it describes P.

Given:

struct S
{
template <class F>
void method(const F& f)
{
f();
}
};

You seem to think "template parameter type (call it P)" is F where as
I think it is F const &.

I just missed the "If P is not a reference type". So in fact, the
reverse is true; rather than choosing the function pointer type for
the template parameter, template argument deduction deduces F=void():

S::method<void()>

Still, as I said before, there is nothing ambiguous about it and
overload resolution doesn't come into it, since 1 function is chosen
by TAD (S::method<void()>) and there is only 1 valid conversion
sequence for the parameter to reach that type (void() ->
void(const&)() (direct reference binding).

The original example compiles fine with Comeau C++:

#include <iostream>
void func()
{ std::cout << "success!\n"; }
struct S
{
template <class F>
void method(const F& f)
{ f(); }
};
int main()
{
S s;
s.method(func);
}

Tom
 
R

Rob Williscroft

tom_usenet wrote in in
comp.lang.c++:
I just missed the "If P is not a reference type". So in fact, the
reverse is true; rather than choosing the function pointer type for
the template parameter, template argument deduction deduces F=void():

S::method<void()>

Yep, I mistakenly assumed a conversion was nessacery for TAD, clearly
it isn't.
Still, as I said before, there is nothing ambiguous about it and
overload resolution doesn't come into it, since 1 function is chosen
by TAD (S::method<void()>) and there is only 1 valid conversion
sequence for the parameter to reach that type (void() ->
void(const&)() (direct reference binding).

Thanks for the update.

Rob.
 

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
474,164
Messages
2,570,898
Members
47,439
Latest member
shasuze

Latest Threads

Top