Topic: Can't match void parms with empty parms in method ptr.
Author: Steve Clamage <stephen.clamage@sun.com>
Date: 2000/03/01 Raw View
On 27 Feb 2000 12:46:24 -0500, Don McFarland <dmcfarland1@home.com>
wrote:
> As another approach to the problem, I'd be interested
>in assessments on the standards-compliance of the following code:
>
> template<class T>
> struct Foo
> {
> Foo(T){}
> Foo(){}
> };
> template Foo<void>;
By definition, void is an incomplete type that cannot be completed.
You cannot have a function parameter of type void. The syntactical
construct "(void)" as a parameter list is a special case that means a
function has no parameters. Templates are not macros, and the meaning
of Foo<void> is that the first constructor for Foo would have a
parameter of type void, which is not allowed. Refer to 8.3.5 paragraph
2, as well as 3.9.1 paragraph 9.
---
Steve Clamage, stephen.clamage@sun.com
[ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
[ 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 <kuyper@wizard.net>
Date: 2000/03/01 Raw View
J rg Barfurth wrote:
....
> template <class Ret, class Arg1, class Arg2>
> struct Function
> {
> typedef Ret result_type;
> typedef Arg1 first_argument_type;
> typedef Arg2 second_argument_type;
> typedef Ret type(Arg1,Arg2); // the function type
> typedef Ret const_type(Arg1,Arg2) const; // also as
const
> };
Is that legal? I thought that 'const' following a function declaration
was meaningful only for member functions, and const_type is a member
typedef for an ordinary (non-member) function type.
[ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
[ 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: scherrey@proteus-tech.com (Benjamin Scherrey)
Date: 2000/02/25 Raw View
I'm told by some good folks from the gcc mailing list that the following =
code
is ill-formed because "Type deduction may fail for the following =
reasons: ...
Attempting to create a function type in which a parameter has a type of =
void."
I was not aware of, nor do I understand this limitation. Additionally, =
the
error the compiler provides seems to imply that the issue is more of a =
problem
with the typedef resolution than the template.
How does one go about fixing this problem in an ANSI compatible manner? =
If the
reason given above is correct, I would presume that specializing an
implementation of my template class for void type parms wouldn't be safe =
either (either way - it still don't work with gcc-2.95.2).
Appreciate your comments/suggestions,
Ben Scherrey
-- snip --
//
// match.cpp - Tests pointer to memberfunction void
// parm resolution problem.
//
template < class To, typename ReturnType, typename ParmType >
class Matcher
{
public:
typedef ReturnType (To::*SendMethod)(ParmType) const;
typedef ReturnType (To::*EmptyMethod)() const;
// This constructor can't match void parm SendMethods.
Matcher( const To& t, const SendMethod sm )
{
}
// This constructor will work, however!
/*
Matcher( const To& t, const EmptyMethod em )
{
}
*/
};
class Test
{
public:
bool testVoid( void ) const { return 0; }
bool testInt( int ) const { return 0; }
};
int main( void )
{
Test ATest;
// Won't work without EmptyMethod constructor.
Matcher< Test, bool, void > M1( ATest, &Test::testVoid );
// Works fine.
Matcher< Test, bool, int > M2( ATest, &Test::testInt );
}
// eof( match.cpp )
[ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/02/26 Raw View
In article <893i7g$3i0p0_002@news.newsguy.com>, Benjamin Scherrey
<scherrey@proteus-tech.com> writes
>//
>// match.cpp - Tests pointer to memberfunction void
>// parm resolution problem.
>//
>
>template < class To, typename ReturnType, typename ParmType >
Why are you using two keywords that have identical meanings in the
context? 'class' and 'typename' are indistinguishable here and have no
significance to the compiler.
>class Matcher
>{
>public:
>
> typedef ReturnType (To::*SendMethod)(ParmType) const;
>
> typedef ReturnType (To::*EmptyMethod)() const;
>
> // This constructor can't match void parm SendMethods.
But of course, 'void' used in the context of a parameter list is NOT a
type but a C construct to allow the distinction between empty parameter
lists and undeclared parameter lists. It is only supported in C++ for
compatibility and has no other significance.
> Matcher( const To& t, const SendMethod sm )
> {
>
> }
>
> // This constructor will work, however!
Why the surprise?
>/*
> Matcher( const To& t, const EmptyMethod em )
> {
> }
>*/
>
>};
>
>class Test
>{
>public:
>
> bool testVoid( void ) const { return 0; }
by writing 'void' in the above you are simply perpetuating the delusion
that it is a type :)
>
> bool testInt( int ) const { return 0; }
>
>};
>
>int main( void )
>{
> Test ATest;
>
> // Won't work without EmptyMethod constructor.
> Matcher< Test, bool, void > M1( ATest, &Test::testVoid );
Now void in this context is a type! An incomplete one, but none-the-less
a type.
>
> // Works fine.
> Matcher< Test, bool, int > M2( ATest, &Test::testInt );
>
>}
So the conclusion is that you must have both ctors and call the
appropriate one.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
[ 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: =?ISO-8859-1?Q?J=F6rg?= Barfurth <joerg.barfurth@germany.sun.com>
Date: 2000/02/26 Raw View
Am 25.02.00, 06:08:58, schrieb scherrey@proteus-tech.com (Benjamin
Scherrey) zum Thema Can't match void parms with empty parms in method
ptr.:
> I'm told by some good folks from the gcc mailing list that the following
=
> code
SNIPPED below. Like my sample baz below, but as a class member (and
taking pointer-to- member).
> is ill-formed because "Type deduction may fail for the following =
> reasons: ...
> Attempting to create a function type in which a parameter has a type of =
> void."
They are right. There is no such thing as a function with a parameter of
type 'void'. And template matching is not text substitution.
int foo(int); // takes one parameter of type int
int bar(void); // doesn't take one parameter of type void
int bar(); // declares the same bar no parameters
template <typename Parm> void baz(int (*)(Parm));
// baz expects a function taking one parameter, so
baz(foo); // legal baz<int> called
baz(bar); // illegal baz<void> not called
> How does one go about fixing this problem in an ANSI compatible manner? =
> If the
> reason given above is correct, I would presume that specializing an
> implementation of my template class for void type parms wouldn't be safe
=
> either (either way - it still don't work with gcc-2.95.2).
> Appreciate your comments/suggestions,
[SNIP OP's CODE]
You could specialize the whole class, but you would need to reimplement
all members.
As usual, you can solve this through one more level of indirection.
With templates indirections spells 'traits'. Traits allow you to
specialize in small chunks which can be reused.
// can easily generalize the following to support more arguments
template <class Ret, class Arg1 = void, class Arg2 = void> struct
Function;
// 2 argument version
template <class Ret, class Arg1, class Arg2>
struct Function
{
typedef Ret result_type;
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Ret type(Arg1,Arg2); // the function type
typedef Ret const_type(Arg1,Arg2) const; // also as const
};
// partially specialize for one arg
template <class Ret, class Arg>
struct Function<Ret, Arg, void>
{
typedef Ret result_type;
typedef Arg argument_type;
typedef Arg first_argument_type;
typedef Ret type(Arg); // the function type
typedef Ret const_type(Arg) const;
};
// partially specialize for no args
template <class Ret>
struct Function<Ret, void, void>
{
typedef Ret result_type;
typedef Ret type(); // the function type
typedef Ret const_type() const;
};
Adjusting the OP's code:
template < class To, typename ReturnType, typename ParmType >
class Matcher
{
public:
typedef typename Function<ReturnType,ParmType>::const_type SendFunc;
typedef SendFunc (To::*SendMethod);
// instead of // typedef ReturnType (To::*SendMethod)(ParmType) const;
// Now this constructor _can_ match void (i.e. no) parm SendMethods.
Matcher( const To& t, const SendMethod sm );
//...
};
struct Test {
bool foo(int) const;
bool bar() const;
};
int main()
{
Test t;
Matcher<Test,bool,int> m_int (t,&Test::foo); // OK
Matcher<Test,bool,void> m_void(t,&Test::bar); // OK
}
You might need to specialize some methods of Matcher for ParmType ==
'void' though. (Can' pass void arguments to a no-argument function)
--
J rg Barfurth
---
[ 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 <kuyper@wizard.net>
Date: 2000/02/26 Raw View
Francis Glassborow wrote:
>
> In article <893i7g$3i0p0_002@news.newsguy.com>, Benjamin Scherrey
> <scherrey@proteus-tech.com> writes
....
> >template < class To, typename ReturnType, typename ParmType >
> Why are you using two keywords that have identical meanings in the
> context? 'class' and 'typename' are indistinguishable here and have no
> significance to the compiler.
Given that they are in fact identical in meaning, the different
spellings can be used as a hint to programmers. I generally use 'class'
when the type must be a class, and 'typename' when it can also be a
built-in type, such as an integer. Whether that's Scherrey's reason, I
don't know. I put this in the same category as using different
capitalization schemes for different types of identifiers.
---
[ 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: scherrey@proteus-tech.com (Benjamin Scherrey)
Date: 2000/02/29 Raw View
In article <20000225.15014829@jb-11116.stardiv.de>, jb@stardivision.de wrote:
<snip>
>You could specialize the whole class, but you would need to reimplement
>all members.
>As usual, you can solve this through one more level of indirection.
>With templates indirections spells 'traits'. Traits allow you to
>specialize in small chunks which can be reused.
>
> // can easily generalize the following to support more arguments
> template <class Ret, class Arg1 = void, class Arg2 = void> struct
>Function;
<rest of example snipped>
Joerg,
I received a few replies about this problem and thought yours was the
most elegant. Unfortunately, it failed to work on g++-2.95.2 under Linux. Is
the problem my poor implementation or the compilers?
thanx & later,
Ben Scherrey
---- cut here ---
//
// match.cpp - Tests pointer to memberfunction void parm
resolution problem.
//
template < class ReturnType, class Parm1 = void, class Parm2 = void >
struct Method;
template < class ReturnType, class Parm1, class Parm2 >
struct Method
{
typedef ReturnType result_type;
typedef Parm1 first_parm_type;
typedef Parm2 second_parm_type;
typedef ReturnType method_type( Parm1, Parm2 );
// Can't do const for some reason!!! typedef ReturnType const_method_type(
Parm1, Parm2 ) const;
};
template < class ReturnType, class Parm1 >
struct Method< ReturnType, Parm1, void >
{
typedef ReturnType result_type;
typedef Parm1 first_parm_type;
typedef ReturnType method_type( Parm1 );
// Can't do const for some reason!!! typedef ReturnType
const_method_type( Parm1 ) const;
};
template < class ReturnType >
struct Method< ReturnType, void, void >
{
typedef ReturnType result_type;
typedef ReturnType method_type();
// Can't do const for some reason!!! typedef ReturnType
const_method_type() const;
};
template < class To, typename ReturnType, typename ParmType >
class Matcher
{
public:
// Old way... typedef ReturnType (To::*SendMethod)(ParmType) const;
typedef typename Method< ReturnType, ParmType >::method_type
SendMethodType;
typedef SendMethodType( To::*SendMethod );
typedef ReturnType (To::*EmptyMethod)() const;
// This constructor can't match void parm SendMethods.
// can't do const now... Matcher( const To& t, const SendMethod sm )
Matcher( To& t, const SendMethod sm )
{
}
/*
COMPLETELY BROKE NOW
// This constructor will work, however!
Matcher( const To& t, const EmptyMethod em )
{
}
*/
};
class Test
{
public:
// bool testVoid( void ) const { return 0; }
bool testVoid( void ) { return 0; }
// bool testInt( int ) const { return 0; }
bool testInt( int ) { return 0; }
};
int main( void )
{
Test ATest;
Matcher< Test, bool, void > M1( ATest, &Test::testVoid );
Matcher< Test, bool, int > M2( ATest, &Test::testInt );
}
// eof( match.cpp )
[ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
[ 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: =?ISO-8859-1?Q?J=F6rg?= Barfurth <joerg.barfurth@germany.sun.com>
Date: 2000/03/06 Raw View
Am 01.03.00, 20:14:36, schrieb James Kuyper <kuyper@wizard.net> zum Them=
a=20
Re: Can't match void parms with empty parms in method ptr.:
> J=F6rg Barfurth wrote:
> > typedef Ret type(Arg1,Arg2); // the function type
> > typedef Ret const_type(Arg1,Arg2) const; // also as const=
> Is that legal? I thought that 'const' following a function declaration=
> was meaningful only for member functions, and const_type is a member
> typedef for an ordinary (non-member) function type.
It is legal (sorry I can't give a reference now).=20
The trailing const on a function declarator declares a valid function=20=
type. Using typedef you can create an alias for such a type. Functions o=
f=20
that type need to be class members though.
BTW: The new beta version of como online=20
(http://www.comeaucomputing.com/tryitout) accepts it.
AFAICS you can only use it like:
<sample>
typedef void Func(int);
typedef void ConstFunc(int) const;
struct X
{
Func foo; // same as: void foo(int);
ConstFunc bar; // same as: void bar(int) const;
};
Func X::*pfoo; // same as: void (X::*pfoo)(int);
ConstFunc X::*pbar; // same as: void (X::*pbar)(int) const;
const X x;
pbar =3D &X::bar;
(x.*pbar)(42);
</sample>
This looks quite obfuscated. It may be useful with templates though (as =
my original post may have shown).=20
But probably it just makes some of the rules about declarations in the=20=
standard more uniform. (The declaration of foo has been possible as show=
n=20
for quite some time. So allowing the const when typedef'ing a function=20=
type removes an 'inconsistency').
--
J=F6rg Barfurth