template<class T>
void someFunc(void (T::*myFunc)() const) { }
class Foo
{
public:
void member() {}
void member() const {}
};
int main()
{
someFunc(&Foo::member); // Should this work?
return 0;
}
I'm hoping the compiler can deduce the template argument T as Foo
based on the member-function pointer. However, this code is rejected
by Visual C++ 2010 with 2 errors on the commented line, that the
function argument is ambiguous, and that it couldn't deduce the
type of T. However, g++ 4.5 and Comeau online accept this code
without errors or warnings.
To get VC++ to compile, I can explicitly state that T is a Foo:
someFunc<Foo>(&Foo::member);
I'll admit is is only a slight annoyance, but it seems unnecessary -
the Foo type is obvious.
Interestingly, VC++ doesn't complain if someFunc's parameter
is changed to be non-const.
So is this a bug in Visual C++ 2010, or are the other compilers
being too "aggressive" in their deductions? Does the standard
specify what can be deduced in a function template?
Regards,
Ryan
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
This is a well-formed C++ program.
> I'm hoping the compiler can deduce the template argument T as Foo
> based on the member-function pointer. However, this code is rejected
> by Visual C++ 2010 with 2 errors on the commented line, that the
> function argument is ambiguous, and that it couldn't deduce the
> type of T. However, g++ 4.5 and Comeau online accept this code
> without errors or warnings.
This must be a compiler bug in VC 2010.
> To get VC++ to compile, I can explicitly state that T is a Foo:
> someFunc<Foo>(&Foo::member);
>
> I'll admit is is only a slight annoyance, but it seems unnecessary -
> the Foo type is obvious.
>
> Interestingly, VC++ doesn't complain if someFunc's parameter
> is changed to be non-const.
Either case is supposed to be supported.
> So is this a bug in Visual C++ 2010, or are the other compilers
> being too "aggressive" in their deductions? Does the standard
> specify what can be deduced in a function template?
Yes, the standard does specify this in [temp.deduct.type]/18:
"A template-argument can be deduced from a function, pointer to
function, or pointer to member function type."
HTH & Greetings from Bremen,
Daniel Krügler
Consider the following modified version if the OP's program:
template<class T>
void someFunc(void (T::*myFunc)() ) { }
class Foo
{
public:
void member() {}
void member() const {}
};
int main()
{
someFunc(&Foo::member);
return 0;
}
The above program does not compile with g++3.4.3:
g++ -std=c++98 -pedantic -Wall -Wextra a.cpp
The following is the compilation error:
a.cpp: In function `int main()':
a.cpp:14: error: no matching function for call to `someFunc(<unknown
type>)'
If I have 'const' for the parameter type of 'someFunc()', then there
is no error. If I remove the 'const', then the above compilation error
appears. Kindly explain why I get this error and help me to fix this
compilation error.
Thanks
V.Subramanian
Even this program is supposed to be well-formed, it
follows the same rules as the one from the OP. Note
that non-static member functions with an cv-qualifier-seq
and those without are completely different types
and no implicit conversion exists in any direction.
Specifically a function template like
template<class T>
void someFunc(void (T::*myFunc)()) {}
can *never* successfully deduce given the following
variant:
struct Foo {
void member() const {}
};
int main() {
someFunc(&Foo::member);
}
Now, there is only one member function with the name
'member', but that cannot instantiate above function
template, because the member function type does not
match.
> If I have 'const' for the parameter type of 'someFunc()', then there
> is no error. If I remove the 'const', then the above compilation error
> appears. Kindly explain why I get this error and help me to fix this
> compilation error.
I can only say that this is a compiler bug. Adding
the cv-qualifier-seq within the template can *only*
instantiate for Foo::member() const, removing that
cv-qualifier-seq can only instantiate for Foo::member().
Note that your program successfully compiles with
newer versions of gcc (with or without -std=c++98 set).
HTH & Greetings from Bremen,
Daniel Krügler
Also note that this programm is not well-formed:
template<typename T, typename C>
void f(T C::*, typename identity<T>::type *);
struct X { void f() const; }
int main() { f(&X::f, 0); }
because "T" is "void()const", but such a type is not allowed as a
function parameter type. If you would pass a "void f();" member
function, it would work.
Your rationale is a bit misleading. This program
is ill-formed, because of the illegal attempt to
form a normal pointer to a member function
type (and of-course because of the missing
semicolon after the definition of X). Your
variant without the cv-qualification does
work, because now a normal function pointer
void (*)() is formed.
The alternative version
template<typename T, typename C>
void f(T C::*);
struct X { void f() const; };
int main() { f(&X::f); }
should be well-formed though, because it
is OK to form the type 'void () const'.
See 8.3.5/9 and 9.3/9 from the FCD or
8.3.5/7 and 9.3/9 from C++03.
HTH & Greetings from Bremen,
Daniel Krügler
> On 26 Aug., 21:49, litb <Schaub-Johan...@web.de> wrote:
> [..]
>> Also note that this programm is not well-formed:
>>
>> template<typename T, typename C>
>> void f(T C::*, typename identity<T>::type *);
>>
>> struct X { void f() const; }
>>
>> int main() { f(&X::f, 0); }
>>
>> because "T" is "void()const", but such a type is not allowed as a
>> function parameter type. If you would pass a "void f();" member
>> function, it would work.
>
> Your rationale is a bit misleading. This program
> is ill-formed, because of the illegal attempt to
> form a normal pointer to a member function
> type (and of-course because of the missing
> semicolon after the definition of X). Your
> variant without the cv-qualification does
> work, because now a normal function pointer
> void (*)() is formed.
>
What I was saying (or trying to say) is that both "void()" and
"void()const"
are normal, though different, function types. However, the second one is
not
allowed by the Standard to appear except as a type in a member pointer
declarator, as the type of a member function declaration or as the toplevel
type in a typedef declaration. See 8.3.5/4. There exist issue #547 about
this though, because it harms generic programming.
There exist no member function types. The Standard has a note about this at
9.2/10.
> The alternative version
>
> template<typename T, typename C>
> void f(T C::*);
>
> struct X { void f() const; };
>
> int main() { f(&X::f); }
>
> should be well-formed though, because it
> is OK to form the type 'void () const'.
> See 8.3.5/9 and 9.3/9 from the FCD or
> 8.3.5/7 and 9.3/9 from C++03.
>
Correct :)
> There exist no member function types. The Standard has a note about this at
> 9.2/10.
This note alone should not be convincing argument.
First, several other non-normative wording use this
term, e.g. see 4.4/3 or footnote 63.
Second, even normative text uses this term, see
5.2.10/9 and 7/4. In the most recent draft (N3126)
the usage of this term has increased again in
normative usage, see 14.8.2.1/6, 14.8.2.5/18, or
15.4/2.
What I agree with is that the standard should either
define this term or should remove its usage. I tend
to prefer the first alternative, because the meaning
of this term is usually well understood.
Greetings from Bremen,
Daniel Krügler
--
> On 29 Aug., 04:37, "Johannes Schaub (litb)" <schaub-johan...@web.de>
> wrote:
>
>> There exist no member function types. The Standard has a note about this
>> at 9.2/10.
>
> This note alone should not be convincing argument.
>
> First, several other non-normative wording use this
> term, e.g. see 4.4/3 or footnote 63.
>
> Second, even normative text uses this term, see
> 5.2.10/9 and 7/4. In the most recent draft (N3126)
> the usage of this term has increased again in
> normative usage, see 14.8.2.1/6, 14.8.2.5/18, or
> 15.4/2.
>
Fair point. Though the wording "pointer to member function type" groups like
"(pointer to member function) type", i.e "R (T::*)(...)", intead of "(point
to) member function type", i.e "T*". Member pointers and pointers are
distinct categories (see 3.9.2/1), thus they always need to special case
these. But this has nothing to do with there being special member function
types. 3.9.2/3 states that explicitly
"Except for pointers to static members, text referring to 'pointers' does
not apply to pointers to members."
After rereading the quoted sections it seems that
the term "pointer to member function type" is supposed
to mean in all cases "{pointer to member function} type"
except for 7.5/4.
> What I agree with is that the standard should either
> define this term or should remove its usage. I tend
> to prefer the first alternative, because the meaning
> of this term is usually well understood.
I withdraw this suggestion, except that 7.5/4 should be
fixed in this regard.
- Greetings from Bremen,