C++11 initializer with ambiguous function id-expression? - c++

In the following C++11 code:
void f(int) {}
void f(double) {}
void (*p)(int) = f;
There are two functions.
The third f identifier is an id-expression and the initializer of p.
In 5.1.1p8 [expr.prim.general]/8 it says:
The type of the [id-expression] is the type of the identifier.
The result is the entity denoted by the identifier. The result is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise.
Given that f could be referring to two different entities with two different types, there is no "the entity" or "the type".
Is there some other text in the standard that addresses this situation?
Do implementations just disambiguate this as an extension or is it required somewhere? (Without some other text one could argue that an implementation could reject the f id-expression as ambiguous.)

The standard (at § 13.4) defines that:
A use of an overloaded function name without arguments is resolved in
certain contexts to a function, a pointer to function or a pointer to
member function for a specific function from the overload set. A
function template name is considered to name a set of overloaded
functions in such contexts. The function selected is the one whose
type is identical to the function type of the target type required in
the context.
Emphasis mine.
After the quote, there is an example (at § 13.4/5) that resembles yours:
int f(double);
int f(int);
int (*pfd)(double) = &f; // selects f(double)
int (*pfi)(int) = &f; // selects f(int)
As far as the unary & is concerned, the standard specifies that (at § 5.3.1/6 and thanks to jogojapan):
The address of an overloaded function can be taken only in a context
that uniquely determines which version of the overloaded function is
referred to.
but can also be omitted (at § 13.4/1):
The overloaded function name can be preceded by the & operator.
(again, emphasis mine) just like you did, in your example.

Related

How to explicitly call a conversion function whose conversion-type-id contains a placeholder specifier

struct A{
operator auto(){
return 0;
}
};
int main(){
A a;
a.operator auto(); // #1
a.operator int(); // #2
}
GCC accepts that #2 is the right way to call the conversion function explicitly while Clang accepts #1.
It seems that #1 is ill-formed due to the following rule:
dcl.spec.auto#6
A program that uses auto or decltype(auto) in a context not explicitly allowed in this section is ill-formed.
This usage a.operator auto() is not explicitly allowed in section [dcl.spec.auto], hence it should be ill-formed. However, for the second usage, which is accepted by GCC, the standard does not say that the conversion-function-id where the conversion-type-id is replaced by the deduced type denotes the name of the conversion function. In other words, the declared conversion-function-id in the declaration is operator auto rather than operator int. The former has the same token as the declarator-id of the declaration. According to the grammar, the unqualified-id operator auto should be the name of that conversion function. So, how to explicitly call this conversion function? Is it underspecified in the standard about which is the name of the conversion function when it contains a placeholder specifier?
It seems, that this is not specified precisely enough.
From 10.1.7.4 The auto specifier:
The placeholder type can appear with a function declarator in the
decl-specifier-seq, type-specifier-seq, conversion-function-id, or
trailing-return-type, in any context where such a declarator is valid.
Reading precisely, one might distinguish here between "can" and the stronger "can only", i.e. potentially opening up room for degrees of freedom for compiler intrinsics (strictly wrong vs. unspecified behavior).
And 3.4.5 class member access says:
7 If the id-expression is a conversion-function-id, its
conversion-type-id is first looked up in the class of the object
expression and the name, if found, is used.
Again leaving room for interpretation if the auto keyword can effectively be a fully qualified conversion-type-id within this context or not.
Your question itself might have to be further branched, namely
What are the overloading rules for the operator auto() usage in detail, i.e. should it be available for regular candidates competition already on class definition level? (not the case for Clang and Gcc, both accept the operator a priori besides an extra operator int() ...)
Can the operator auto() be called with explicit member operator referring (your case 1), i.e. effectively, has it a (unique) accessible name? Allowing that would be contradictory to all other explicitly allowed use cases for the keyword.
I've seen explicit tests for this within several clang revisions so its behavior is not an artefact of implicit naming convention applicance but an explicitly desired behavior obviously.
As already mentioned within the comments, Clang's behavior is a bit more overall consistent here at least in comparison to gcc since it's totally clear there, where the auto keyword is used for type deduction and where for name / function-id resolution. The operator auto() there is handled as a more explicit own entity, whereas for gcc, it has anonymous character similar to a lambda but is involved within candidates competition even for the explicit member operator access way.

Is a pointer to function (sometimes/always?) a function declarator?

(This question has been broken out from the discussion to this answer, which highlights CWG 1892)
Some paragraphs of the standard applies specific rules to function declarators; e.g. [dcl.spec.auto]/3 regarding placeholder types [emphasis mine]:
The placeholder type can appear with a function declarator in the decl-specifier-seq, type-specifier-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function declarator includes a trailing-return-type ([dcl.fct]), that trailing-return-type specifies the declared return type of the function. Otherwise, the function declarator shall declare a function. [...]
restricts where placeholder types may appear with(in) a function declarator. We may study the following example:
int f() { return 0; }
auto (*g)() = f; // #1
which both GCC and Clang accepts, deducing g to int(*)().
Is a pointer to function (sometimes/always?) a function declarator?
Or, alternatively, applied to the example, should #1 be rejected as per [dcl.spec.auto]/3, or does the latter not apply here as a pointer to function is not a function declarator (instead allowing #1 as per [dcl.spec.auto]/4 regarding variable type deduction from initializer)?
The rules for what is a given declarator is not entirely easy to follow, but we may note that, from [dcl.decl]/1
A declarator declares a single variable, function, or type, within a declaration.
that a given declarator is either any of a variable declarator, a function declarator or a type declarator.
[dcl.ptr] covers (variable) declarators that are pointers, but does not explicitly (/normatively) mention pointers to functions, albeit does so non-normatively in [dcl.ptr]/4
[dcl.fct] covers function declarators but does not mention function pointers as part of function declarations, other than a note that function types are checked during assignment/initialization to function pointers (which is not relevant for what a function declarator is)
My interpretation is that #1 is legal (as per the current standard), as it falls under a variable declarator. If this is actually correct, then the extended question (from the linked thread) is whether
template<auto (*g)()>
int f() { return g(); }
is legal or not (/intended to be legal or not as per CWG 1892); as the template parameter arguably contains a declarator that is a function pointer declarator, and not a function declarator.
We may finally note, as similarly pointed out in the linked to answer, that
template<auto g()> // #2
int f() { return g(); }
is arguably ill-formed (although this example is also accepted by both GCC and Clang), as the non-type template parameter at #2 is a function declarator and is thus used in an illegal context as per [dcl.spec.auto]/3, as it does not contain a trailing return type and does not declare a function.
The confusion here arises from two different meanings of "declarator": one is the portion of a declaration (after the specifiers) that pertains to one entity (or typedef-name), while the other is any of the several syntactic constructs used to form the former kind. The latter meaning gives rise to the grammar productions ptr-declarator (which also covers references) and noptr-declarator (which includes functions and arrays). That meaning is also necessary to give any meaning to a restriction that a "function declarator shall declare a function". Moreover, if we took the variable declaration
auto (*g)() = /*…*/;
to not involve a "function declarator" for the purposes of [dcl.spec.auto.general]/3, we would not be able to write
auto (*g)() -> int;
which is universally accepted (just as is the similar example in the question).
Moreover, while the statement that checks whether "the function declarator includes a trailing-return-type" inevitably refers to an overall declarator (which is what supports a trailing-return-type), it does so in its capacity as a "declaration operator" because it still allows the above cases with nested use of such operators. (What that limitation forbids is just
auto *f() -> int*;
where deduction would work but isn't performed at all here because it would always be useless.)
Meanwhile, there is some evidence, beyond implementation consensus, that the answer to the higher-level question is that auto in these cases should be allowed: [dcl.spec.auto.general]/1 says that auto in a function parameter serves to declare a generic lambda or abbreviated function template "if it is not the auto type-specifier introducing a trailing-return-type" rather than if it is not used with a function declarator at all.

msvc visual c++ incorrect formation of bound member function expression from static member function

Consider the following code:
#include <type_traits>
struct A {
template<typename T, std::enable_if_t<sizeof(T)<=sizeof(int), int> = 0>
static void fun() {}
template<typename T, std::enable_if_t<(sizeof(T)>sizeof(int)), int> = 0>
static void fun() {}
void test() {
using fun_t = void(*)();
fun_t ff[] = {
fun<int>,
&fun<int>,
A::fun<int>,
&A::fun<int>,
this->fun<int>,
&this->fun<int>, //error C2276: '&': illegal operation on bound member function expression
};
}
};
msvc 2015update3 and 2017rc generate error C2276, which makes no sense. gcc, clang and intel compiler are fine.
The work-around is simple: use any of the other expressions above which should all be equivalent.
However, the wording of the error message is disturbing, and one has to wonder, if a bound member function expression is incorrectly formed for any of the other alternatives.
Any insights into this matter?
This is a nice, dark corner of the standard for the language lawyers to feast upon.
[expr.ref] ¶4.3
If E2 is a (possibly overloaded) member function, function overload resolution is used to determine whether E1.E2 refers to a static or a non-static member function.
If it refers to a static member function and the type of E2 is "function of parameter-type-list returning T", then E1.E2 is an lvalue; the expression designates the static member function. The type of E1.E2 is the same type as that of E2, namely "function of parameter-type-list returning T".
Otherwise, if E1.E2 refers to a non-static member function and the type of E2 is "function of parameter-type-list cv ref-qualifieropt returning T", then E1.E2 is a prvalue. The expression designates a non-static member function. The expression can be used only as the left-hand operand of a member function call. The type of E1.E2 is "function of parameter-type-list cv returning T".
It goes without saying that only pointers to static member functions can be formed by the member access expression (i.e. dot or arrow operator). What is to be noted, though, is that overload resolution determines the "staticness" of a member function. So the question is, how can overload resolution act without an argument list? Compilers seem to differ on their interpretation.
Some compilers may recognize that because the expression is being used to form a pointer to a function, the function must be a static member function or else the program is ill formed, and so exclude non-static member functions from the set of candidate functions.
Other compilers may recognize that because all of the overloads are static, overload resolution can not possibly select a non-static member function, and so skip the step altogether.
Yet other compilers may give up entirely, faced with the instruction to apply overload resolution without any argument list.
This is a related example:
struct A {
static void foo(int) {}
static void bar(int) {}
static void bar(double) {}
};
void test() {
A a;
void(*f)(int) = a.foo; // gcc:OK, msvc:OK, clang:OK
void(*g)(int) = a.bar; // gcc:OK, msvc:OK, clang:ERROR
void(*h)(int) = &a.bar; // gcc:OK, msvc:ERROR, clang:ERROR
}
Here Clang is unable to form a pointer to the int overload of bar using the member access expression, with or without the & address-of operator. MSVC is inconsistent in that it succeeds without the & but not with it. But for the aforementioned reasons it is difficult to say which is conformant. GCC is quite happy in all cases to let the member access expression designate an unresolved overload that is then resolved due to the target type of the initialization ([over.over] ¶1).
It gets even more interesting when SFINAE gets involved:
[temp.over] ¶1
...If, for a given function template, argument deduction fails or the synthesized function template specialization would be ill-formed, no such function is added to the set of candidate functions for that template...
Thus, some compilers may exclude SFINAE failures from the set of candidate functions for overload resolution for the purpose of determining the "staticness" of a member function. But again, it is hard to say what is conformant here. This may explain why Clang accepts the example in the original question, but not my bar example. I get the feeling implementors are just trying their best to fill in the blanks here.

Qualified-ids, are they lvalues or prvalues?

I was trying to validate this statement (my emphasis) in paragraph §5.1.1/8 (page 87) of the C++11 Standard
A nested-name-specifier that denotes a class, optionally followed by
the keyword template (14.2), and then followed by the name of a member
of either that class (9.2) or one of its base classes (Clause 10), is
a qualified-id; 3.4.3.1 describes name lookup for class members that
appear in qualified-ids. The result is the member. The type of the
result is the type of the member. The result is an lvalue if the
member is a static member function or a data member and a prvalue
otherwise.
with the following snippet:
#include <iostream>
namespace N {
class A {
public:
int i;
void f();
};
}
int main()
{
std::cout << &N::A::f << '\n';
std::cout << &N::A::i << '\n';
}
clang and gcc compile this code and VS2013 requires the definition of the member function f.
All three of them print
1
1
but I have no idea where these numbers come from.
live example
According to the paragraph highlighted above the expressions N::A::f is a prvalue, as f is not a static member function. Nonetheless, I was able to take its address in the code.
At the same time, in §5.3.1/3 one reads (emphasis mine):
The result of the unary & operator is a pointer to its operand. The
operand shall be an lvalue or a qualified-id. If the operand is a
qualified-id naming a non-static member m of some class C with type T,
the result has type “pointer to member of class C of type T” and is a
prvalue designating C::m.
which gives the impression that neither N::A::f nor N::A::i are lvalues, as they are qualified-ids.
but I have no idea where these numbers come from.
Pointer-to-members aren't pointers. No operator<< can output their original value, the best and only match is the one that outputs bool values. Thus they are converted to bool (which obviously yields true) and the output is 1. Try to insert std::boolalpha and check the output again.
Nonetheless, I was able to take its address in the code.
How is that a surprise to you? You quoted the part that allows and explains this exact construct. It clearly states that taking the adress of a qualified-id that names a non-static member designates that member.
qualified-ids are not only lvalues or rvalues. It completely depends on context. If they designate non-static members from outside that members class or any subclass of it, they have to be prvalues as they don't designate any specific object but rather a value (or information, in other words -- the type and an offset).

Pointer to member function weirdness

I'm trying to do some binding with my C++ code, and use pointer to member functions.
I have the following code :
class A
{
explicit A(float);
}
class B
{
void setA(A);
void setA(float);
}
Then I declare the pointer to member functions :
(void (B::*)(A))&B::setA
(void (B::*)(float))&B::setA
The compiler (MSVC11) finds the second line is ambiguous.
If I comment setA(A) in class B, both lines are considered ok by the compiler (!)
Is it a compiler bug?
Is there a way to circumvent that, without modifying class B's signature?
EDIT :
Actually, the code I posted was oversimplified from my real classes and did compile..
Here's a modified version that really reproduces the bug :
class A
{
public:
explicit A(float f=1.0f, float g=1.0f) {}
};
class B
{
public:
void setA(A){}
void setA(float f, float g=1.0f){}
};
with
(void (B::*)(A))&B::setA
(void (B::*)(float))&B::setA
(void (B::*)(float,float))&B::setA
The 2nd line brings a compile error :
error C2440: 'type casting' : impossible to convert 'overloaded-function' to 'void (__thiscall B::* )(float)'
I would say this is a bug. Per Paragraph 13.4/1 of the C++11 Standard:
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a
pointer to function or a pointer to member function for a specific function from the overload set. [...] . The function selected
is the one whose type is identical to the function type of the target type required in the context. [...] The target can be
— an object or reference being initialized (8.5, 8.5.3),
— the left side of an assignment (5.17),
— a parameter of a function (5.2.2),
— a parameter of a user-defined operator (13.5),
— the return value of a function, operator function, or conversion (6.6.3),
— an explicit type conversion (5.2.3, 5.2.9, 5.4), or
— a non-type template-parameter (14.3.2).
Since it is pretty clear which member function from the overload set has a signature identical to the one you are explicitly casting it to, your code is legal.
Besides, your code compiles fine with Clang 3.2, GCC 4.7.2, GCC 4.8, ICC 13.0.1 and (!) VC10. See, for instance, this live example.
EDIT:
The new code you posted is indeed illegal.
The second cast cannot be resolved, because none of the member functions setA() takes only one float parameter. Therefore, the compiler doesn't know which function you mean by the expression &B::setA. Normally, it would try to disambiguate based on the contextual explicit conversion, but that doesn't help, because it specifies a signature which is incompatible with the signature of both overloads of setA().
If you are wondering why this is the case and why the second overload is not picked, then the reason is that a parameter with a default argument is still a formal parameter of your function (even if it could be omitted in some calls), and its type still counts as part of the function's signature.
Default arguments, on the other hand, are not part of a function's signature:
1.3.20 [defns.signature.member]
signature
<class member function> name, parameter type list (8.3.5), class of which the function is a member, cv-qualifiers (if any), and ref-qualifier (if any)
Now if you remove the overload setA(A), the compiler does know what member function the expression &B::setA refers to, because there is only one. No need to use the explicit cast in order to resolve the expression.
Then, since function pointers can be cast to function pointers of other types, the compiler performs an additional conversion to the specified target type.