Function pointer as template argument

Y

ymost

Hi,
I have a code that generates: "internal compiler error: Segmentation
fault" while compiling with gcc-4 (both on linux and on windows).
Here it is:

//--------------------------------------------------------------------
template< typename T,typename T2 > T addw(T x,T2 y) {return x+(T)y;};

template< typename T > struct A {
template< typename T2,T (* const operation)(T,T2) > struct B {};
template< typename T2 > friend const B< T2,addw<T,T2> > func(T x, T2
y) {return B< T2,addw<T,T2> >();};
};

int main() {
A<double> a,b;
func(1.2,1.3); // <-- Segmentation fault received here
return 0;
}
//--------------------------------------------------------------------

Can anyone tell if there is a problem with this code, or is this just
a compiler bug?
The only special "feature" I can see here is using a function pointer
as a template argument, but under different circumstances it works
fine...
 
K

Kai-Uwe Bux

Hi,
I have a code that generates: "internal compiler error: Segmentation
fault" while compiling with gcc-4 (both on linux and on windows).
Here it is:

//--------------------------------------------------------------------
template< typename T,typename T2 > T addw(T x,T2 y) {return x+(T)y;};

template< typename T > struct A {
template< typename T2,T (* const operation)(T,T2) > struct B {};
template< typename T2 > friend const B< T2,addw<T,T2> > func(T x, T2
y) {return B< T2,addw<T,T2> >();};
};

int main() {
A<double> a,b;
func(1.2,1.3); // <-- Segmentation fault received here
return 0;
}
//--------------------------------------------------------------------

Can anyone tell if there is a problem with this code, or is this just
a compiler bug?

An "internal compiler error" is always a bug in the compiler, regardless of
whether your code is sound or buggy.
The only special "feature" I can see here is using a function pointer
as a template argument, but under different circumstances it works
fine...

I am not sure whether the lookup rules will ensure that the func() is found.


Best

Kai-Uwe Bux
 
A

alfps

An "internal compiler error" is always a bug in the compiler, regardless of
whether your code is sound or buggy.


I am not sure whether the lookup rules will ensure that the func() is found.

After removing syntactically incorrect semicolon,


Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for
ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 12: error: identifier "func" is undefined
func(1.2,1.3); // <-- Segmentation fault received here
^


Comeau's answer is probably the closest to definitive one gets about
what the code means.

The practical answer, taking into account that the rules for friend
function definitions in classes were changed during standardization,
and that about 0% of C++ programmers know them, is to avoid using that
feature.


Cheers,

- Alf
 
N

Noah Roberts

alfps said:
After removing syntactically incorrect semicolon,


Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for
ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 12: error: identifier "func" is undefined
func(1.2,1.3); // <-- Segmentation fault received here
^

Yeah. I big DUH on that one. :p
 
K

Kai-Uwe Bux

alfps said:
After removing syntactically incorrect semicolon,


Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for
ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing. All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 12: error: identifier "func" is undefined
func(1.2,1.3); // <-- Segmentation fault received here
^


Comeau's answer is probably the closest to definitive one gets about
what the code means.

The practical answer, taking into account that the rules for friend
function definitions in classes were changed during standardization,
and that about 0% of C++ programmers know them, is to avoid using that
feature.

Fair enough. I find friend function definitions inside class (templates)
useful. Most of the time, the rules in the standard do the RightThing(tm),
at least for me. But I always have one of the arguments to be of the type
of the class (i.e., I use those friends for operator<< or operator<). Here,
we have the added trickyness that func() is called with two doubles and
nothing hints at A<double> as the point where this version of func() is
declared. I agree that (a) Comeau is probably right and (b) one is better
off staying away from those cases.


Best

Kai-Uwe Bux
 
Y

ymost

Fair enough. I find friend function definitions inside class (templates)
useful. Most of the time, the rules in the standard do the RightThing(tm),
at least for me. But I always have one of the arguments to be of the type
of the class (i.e., I use those friends for operator<< or operator<). Here,
we have the added trickyness that func() is called with two doubles and
nothing hints at A<double> as the point where this version of func() is
declared. I agree that (a) Comeau is probably right and (b) one is better
off staying away from those cases.

Best

Kai-Uwe Bux

Thank you for testing the code on the Comeau compiler, but I fail to
understand why func is undefined, since the following code compiles
and runs just fine on gcc:

//-------------------------------------------------------------
template<typename T> struct A {
template<typename T2> struct B {};
template<typename T2> friend const B<T2> func(T x, T2 y){return B<T2>
();};
};

int main() {
A<double> a,b;
func(1.2,1.3);
return 0;
}
//-------------------------------------------------------------

The only difference here is in the return value of func, so as I
understand it, it should not influence whether func is defined or not.
Can anyone say what exactly makes the difference between the two
cases?
 
Y

ymost

Thank you for testing the code on the Comeau compiler, but I fail to
understand why func is undefined, since the following code compiles
and runs just fine on gcc:

//-------------------------------------------------------------
template<typename T> struct A {
  template<typename T2> struct B {};
  template<typename T2> friend const B<T2> func(T x, T2 y){return B<T2>
();};

};

int main() {
  A<double> a,b;
  func(1.2,1.3);
  return 0;}

//-------------------------------------------------------------

The only difference here is in the return value of func, so as I
understand it, it should not influence whether func is defined or not.
Can anyone say what exactly makes the difference between the two
cases?

To stress this point further:
It has been said here that one shouldn't use friend function
definitions in classes. But even if I move the definition of the
function from the class, I get the compile-time Segmentation fault.
And what really confuses me, is that if I remove the friend
declaration from the class, the code compiles and runs just fine:

//------------------------------------------------------------------------
template<typename T,typename T2> T addw(T x,T2 y) {return x+(T)y;}

template<typename T> struct A {
template<typename T2,T (* const operation)(T,T2)> struct B {};
// When I remove the following line the code compiles and runs:
template<typename T2> friend const B<T2,addw<T,T2> > func(T x, T2
y);
};

template<typename T,typename T2>
const typename A<T>::template B<T2,addw<T,T2> > func(T x, T2 y) {
return typename A<T>::template B<T2,addw<T,T2> >();
};

int main() {
A<double> a,b;
func(1.2,1.3);
return 0;
}
//------------------------------------------------------------------------

I am seriously confused here...
 
J

James Kanze

Note that in this case, it is not the rules for friend function
definitions in classes that were changed, but the rules for name
lookup, in general. But you're probably right that most C++
programmers don't know them. (Not 0%, of course. I know of at
least three people who know them. All of whom work for EDG:).)

That's the key. The Barton-Nackman techique depends on it, and
is wide-spread enough that the committee considered not breaking
it a make or break criteron for any changes.

Also, there's no problem with defining a friend function inside
a class IF the function is correctly declared outside the class.
The problem is that in this case, it's not one function he
wants, but an infinite number of them, so this solution isn't
applicable in this case. (In other cases, it's the way to go.)
Another solution would be to declare and define func as a
function template (outside the class template), and make the
instantiation a friend.
Thank you for testing the code on the Comeau compiler, but I
fail to understand why func is undefined, since the following
code compiles and runs just fine on gcc:
//-------------------------------------------------------------
template<typename T> struct A {
template<typename T2> struct B {};
template<typename T2> friend const B<T2> func(T x, T2 y){return B<T2>
();};
};
int main() {
A<double> a,b;
func(1.2,1.3);
return 0;}
//-------------------------------------------------------------

It shouldn't. The code is clearly illegal, under the current
rules. (It was legal under the pre-standard rules, which
predated namespaces.)

I don't know what changing the return type changes how the
compiler handles this, but it is clearly an error in the
compiler.
The only difference here is in the return value of func, so as
I understand it, it should not influence whether func is
defined or not. Can anyone say what exactly makes the
difference between the two cases?

The difference is probably that Alf compiled the code on a very
close to standards conformant compiler, and you're compiling on
g++, and you've hit a bug in g++. (The g++ development team
will accept the bug report no questions asked. As Kai-Uwe said,
any time the compiler core dumps, it is a bug.) As for the
version which compiles with g++, you've have to ask them; I
think that from version 4.0 on, they would consider it a bug.
(I.e. they intended for this to work correctly from 4.0 on.)
 
J

Joe Smith

To stress this point further:
It has been said here that one shouldn't use friend function
definitions in classes. But even if I move the definition of the
function from the class, I get the compile-time Segmentation fault.
And what really confuses me, is that if I remove the friend
declaration from the class, the code compiles and runs just fine:

[snip code]

I am seriously confused here...

Comeau C++ does not like that code you just posted, even with the friend
line commented out. However, I have no idea why. Can somebody more familar
with the lookup rules explain what why?
 
J

James Kanze

To stress this point further:
It has been said here that one shouldn't use friend function
definitions in classes. But even if I move the definition of
the function from the class, I get the compile-time
Segmentation fault. And what really confuses me, is that if
I remove the friend declaration from the class, the code
compiles and runs just fine:
[snip code]
I am seriously confused here...
Comeau C++ does not like that code you just posted, even with
the friend line commented out. However, I have no idea why.
Can somebody more familar with the lookup rules explain what
why?

Isn't the real question just the opposite: why would anyone
expect the code to work? The only declaration of func is in the
class template A, so normally, the only place func should be
visible is from within the class template A; certainly not from
main.

Practically, of course, the declaration declares a function
which is not a member of A, but is in the nearest surrounding
namespace scope. And although were a declaration is visible and
where what is being declared is found are two orthogonal issues,
in practice, early C++ "injected" the names of friend functions
into file scope. (This was before templates.) During
standardization, the committee found some problems with this,
and dropped it; the only known use of it was the Barton and
Nackman trick, and this ended up covered by ADL, so it was no
longer needed there.
 
J

Joe Smith

James said:
Isn't the real question just the opposite: why would anyone
expect the code to work? The only declaration of func is in the
class template A, so normally, the only place func should be
visible is from within the class template A; certainly not from
main.

I was asking why the new code, that defines the function outside of the
class does not work, even when the friend declaration is omited.

In other words, why does Comeau not like the following:

----------------------------------
template<typename T,typename T2> T addw(T x,T2 y) {return x+(T)y;}

template<typename T> struct A {
template<typename T2,T (* const operation)(T,T2)> struct B {};
};

template<typename T,typename T2>
const typename A<T>::template B<T2,addw<T,T2> > func(T x, T2 y) {
return typename A<T>::template B<T2,addw<T,T2> >();
}

int main() {
A<double> a,b;
func(1.2,1.3);
return 0;
}
----------------------------------

I get the following error:
------
"ComeauTest.c", line 14: error: no instance of function template "func"
matches the
argument list
The argument types that you used are: (double, double)
func(1.2,1.3);

------


If I change the line to "func<double,double>(1.2,1.3);", I still get the
same error.



If I replace func's definition with:
-----------------
template<typename T>
const typename A<T>::template B<double,addw<T,double> > func(T x, double y)
{
return typename A<T>::template B<double,addw<T,double> >();
}
-----------------
I still get the error.


On the other hand, the following replacement works:
-----------------
template<typename T2>
const typename A<double>::template B<T2,addw<double,T2> > func(double x, T2
y) {
return typename A<double>::template B<T2,addw<double,T2> >();
}
 
J

James Kanze

James Kanze wrote:
I was asking why the new code, that defines the function
outside of the class does not work, even when the friend
declaration is omited.
In other words, why does Comeau not like the following:
template<typename T> struct A {
template<typename T2,T (* const operation)(T,T2)> struct B {};
};
template<typename T,typename T2>
const typename A<T>::template B<T2,addw<T,T2> > func(T x, T2 y) {
return typename A<T>::template B<T2,addw<T,T2> >();
}
int main() {
A<double> a,b;
func(1.2,1.3);
return 0;
}
----------------------------------
I get the following error:
------
"ComeauTest.c", line 14: error: no instance of function template "func"
matches the
argument list
The argument types that you used are: (double, double)
func(1.2,1.3);
------

This looks to me like a bug in Comeau.
If I change the line to "func<double,double>(1.2,1.3);", I
still get the same error.

Because it doesn't change anything?

Note that even in this case, template argument deduction occurs,
and can fail. But none of the reasons given for failure seem to
apply here: there can't be any ambiguity with regards to the
type (which in fact was also true in the previous version), and
none of the cases in the list in §14.8.2/2 (Those following the
statement "Type deduction may fail for the following reasons:")
seem to apply.
If I replace func's definition with:
-----------------
template<typename T>
const typename A<T>::template B<double,addw<T,double> > func(T x, double y)
{
return typename A<T>::template B<double,addw<T,double> >();}
On the other hand, the following replacement works:
-----------------
template<typename T2>
const typename A<double>::template B<T2,addw<double,T2> > func(double x, T2
y) {
return typename A<double>::template B<T2,addw<double,T2> >();}
-----------------
And of course, a non-template func works just fine.
What is going on here?

I'd report a compiler bug to Comeau. With the three
cases---there's probably a good hint in them as to where the bug
is (for someone who knows the compilers internals, of course).
(Note, for example, that in the last case, the template A is
resolved when the function template func is defined; in the
other two cases, only when it is instantiated. I would guess
that these are handled in different places in the compiler.)
 

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

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top