C++ - Constructor overloading - private and public - c++

Can you tell me why the following code is giving me the following error - call of overloaded "C(int)" is ambiguous
I would think that since C(char x) is private, only the C(float) ctor is visible from outside and that should be called by converting int to float.
But that's not the case.
class C
{
C(char x)
{
}
public:
C(float t)
{
}
};
int main()
{
C p(0);
}

This is discussed in "Effective C++" by Scott Meyer. The reason this is ambiguous is that they wanted to ensure that merely changing the visibility of a member wouldn't change the meaning of already-existing code elsewhere.
Otherwise, suppose your C class was in a header somewhere. If you had a private C(int) member, the code you present would call C(float). If, for some reason, the C(int) member was made public, the old code would suddenly call that member, even though neither the old code, nor the function it called had changed.
EDIT: More reasons:
Even worse, suppose you had the following 2 functions:
C A::foo()
{
return C(1.0);
}
C B::bar()
{
return C(1.0);
}
These two functions could call different functions depending on whether either foo or bar was declared as a friend of C, or whether A or B inherits from it. Having identical code call different functions is scary.
(That's probably not as well put as Scott Meyer's discussion, but that's the idea.)

0 is an int type. Because it can be implicitly cast to either a float or char equally, the call is ambiguous. Visibility is irrelevant for these purposes.
Either put 0.0, 0., or 0.0f, or get rid of the C(char) constructor entirely.
Edit: Relevant portion of the standard, section 13.3:
3) [...] But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases:
First, a subset of the candidate functions—those that have the proper number of arguments and meet certain other conditions—is selected to form a set of viable functions (13.3.2).
Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.
4) If a best viable function exists and is unique, overload resolution succeeds and produces it as the result. Otherwise overload resolution fails and the invocation is ill-formed. When overload resolution succeeds, and the best viable function is not accessible (clause 11) in the context in which it is used, the program is ill-formed.
Note that visibility is not part of the selection process.

I don't think that:
C p(0);
is being converted to:
C(float t)
you probably need to do:
C p(0.0f);

Related

Can a friend function in C++ have a default argument whose type has a private destructor?

In the next example the class U with private destructor has a friend function foo. And this friend function has argument of type U with default value U{}:
class U{ ~U(); friend void foo(U); };
void foo(U = {});
Clang and MSVC accept this code, but GCC rejects it with the error
error: 'U::~U()' is private within this context
2 | void foo(U = {});
| ^
Demo: https://gcc.godbolt.org/z/eGxYGdzj3
Which compiler is right here, and does friendship extend on default arguments in C++?
C++20 [class.access]/8 provides as follows:
The names in a default argument (9.3.3.6) are bound at the point of declaration, and access is checked at that point rather than at any points of use of the default argument. Access checking for default arguments in function templates and in member functions of class templates is performed as described in 13.9.1.
However, [expr.call]/8 says:
... The initialization and destruction of each parameter
occurs within the context of the calling function. [Example: The access of the constructor, conversion functions or destructor is checked at the point of call in the calling function. ...
While the "Example" text is not normative, I believe it reflects the intent; therefore, in order to read these two provisions harmoniously, we should understand that the destructor of the type of the default argument is (in my opinion, at least) not a name "in a default argument". Instead, we should view the call to the friend function as occurring in the following stages:
The default argument initializer is evaluated. Due to [class.access]/8, access control during this step is done from the context of the declaration.
The parameter is copy-initialized from the result of step 1. Due to [expr.call]/8, access control during this step is done from the context of the calling function.
The function body is evaluated.
The parameter is destroyed. Again, access control is done from the context of the calling function (irrelevant note: when exactly the destruction happens is not completely specified).
GCC shouldn't be rejecting the declaration void foo(U = {}) as there is no actual use of the destructor yet; and indeed, it is possible that foo might be called only from contexts that have access to U::~U. But if foo is called from a context that doesn't have access to U::~U, the program should be ill-formed. In such cases, I think that Clang and MSVC are wrong, because they still accept the code.
However, there is also the issue of [dcl.fct.default]/5 which states:
The default argument has the same semantic constraints as the initializer in a declaration of a variable of the parameter type, using the copy-initialization semantics (9.4). The names in the default argument are bound, and the semantic constraints are checked, at the point where the default argument appears. ...
The standard never defines what it means by "semantic constraints"; if it's assumed to include access control for both the initialization and destruction, then that might explain why Clang and MSVC seem to allow calls to foo from contexts that ought not to have access to U::~U.
But thinking about this more, I feel that this doesn't make too much sense, because it would imply that default arguments are "special" in a way that I don't think was intended. To wit, consider:
class U {
public:
U() = default;
U(const U&) = default;
private:
~U() = default;
friend void foo(U);
};
void foo(U = {}) {}
int main() {
auto p = new U();
foo(*p); // line 1
foo(); // line 2
}
Here, MSVC accepts both lines 1 and 2; it seems clearly wrong to accept line 1, considering how [expr.call]/8 requires the destructor to be accessible from main. But Clang accepts line 2 and rejects line 1, which also seems absurd to me: I don't feel that the intent of the standard was that choosing to use the default argument (as opposed to providing the argument yourself) would exempt the caller from having to have access to the destructor of the parameter type.
If [dcl.fct.default]/5 appears to require Clang's behaviour, then I believe that it should be considered defective.

Unexpected ambiguity of surrogate call functions in C++

On the following code clang and EDG diagnose an ambiguous function call, while gcc and Visual Studio accept the code.
struct s
{
typedef void(*F)();
operator F(); //#1
operator F() const; //#2
};
void test(s& p)
{
p(); //ambiguous function call with clang/EDG; gcc/VS call #1
}
According to the C++ standard draft (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf) section 13.3.1.1.2 2 says;
a surrogate call function with the unique name call-function and having the form R call-function ( conversion-type-id F, P1 a1, ... ,Pn an) { return F (a1,... ,an); } is also considered as a candidate function.
In the code above that seems to mean that two call function definitions (one for each conversion function) are being considered, but both call functions have identical signatures (therefore the ambiguity) since the cv-qualifiers of the conversion operator do not seem to be taken into account in the call function signature.
I would have expected #1 to be called as with gcc and Visual Studio. So if clang/EDG are instead right in rejecting the above code, could someone please shed some light on the reason as to why the standard stipulates that there should be an ambiguity in this case and which code benefits from that property of surrogate call functions? Who is right: clang(3.5)/EDG(310) or gcc (4.8.2)/VS(2013)?
Clang and EDG are right.
Here's how this works. The standard says (same source as your quote):
In addition, for each non-explicit conversion function declared in T of the form
operator conversion-type-id () attribute-specifier-seq[opt] cv-qualifier ;
where [various conditions fulfilled in your example], a surrogate call function with the unique name call-function and having the form
R call-function ( conversion-type-id F, P1 a1, ... ,Pn an) { return F (a1, ... ,an); }
is also considered as a candidate function. [do the same for inherited conversions]^128
And the footnote points out that this may yield multiple surrogates with undistinguishable signatures, and if those aren't displaced by clearly better candidates, the call is ambiguous.
Following this scheme, your type has two conversion operators, yielding two surrogates:
// for operator F();
void call-function-1(void (*F)()) { return F(); }
// for operator F() const;
void call-function-2(void (*F)()) { return F(); }
Your example does not contain any other candidates.
The compiler then does overload resolution. Because the signatures of the two call functions are identical, it will use the same conversion sequence for both - in particular, it will use the non-const overload of the conversion function in both cases! So the two functions cannot be distinguished, and the call is ambiguous.
The key to understanding this is that the conversion that is actually used in passing the object to the surrogate doesn't have to use the conversion function the surrogate was generated for!
I can see two ways GCC and MSVC may arrive at the wrong answer here.
Option 1 is that they see the two surrogates with identical signatures, and somehow meld them into one.
Option 2, more likely, is that they thought, "hey, we don't need to do the expensive searching for a conversion for the object here, we already know that it will use the conversion function that the surrogate was generated for". It seems like a sounds optimization, except in this edge case, where this assumption is wrong. Anyway, by tying the conversion to the source conversion function, one of the surrogates uses identity-user-identity as the conversion sequence for the object, while the other uses const-user-identity, making it worse.

Ambiguous call to overloaded static function

I'm confused by this situation and googling didn't give me the answer. Basically I have the following simple code that doesn't compile:
#include <iostream>
class A
{
public:
int a(int c = 0) { return 1; }
static int a() { return 2; }
};
int main()
{
std::cout << A::a() << std::endl;
return 0;
}
In compiling this, GCC 4.2 says the call to A::a() in main() is ambiguous with both versions of a() valid candidates. Apple's LLVM compiler 3.0 compiles with no error.
Why is gcc confused about which function I want to call? I thought it was obvious that by qualifying a() with A:: I'm asking for the static version of the function. Naturally this code still doesn't compile if I remove the static function a(), because A::a() is not valid syntax for calling the non-static a().
Thanks for any comment!
The reason for this is because C++ specifies that this is ambiguous. Overload resolution specifies that for A::a, since this is not in scope, the argument list in that call is augmented by a contrived A object argument, instead of *this. Overload resolution does not exclude non-static member functions, but instead
If the argument list is augmented by a contrived object and overload resolution selects one of the non-static member functions of T, the call is ill-formed.
This has recently been subject of extensive discussion both in the committee in context of core issue 1005. See core issue 364 which considered changing this rule but didn't do so.
The reason is name resolution happens before anything else the compiler does, like figuring out which overloaded function to use.
Qualifying the function with A:: simply tells the compiler to "look inside of A to find the name a". It doesn't actually help resolve which function you are referring to.
EDIT
And so when you type A::a(), first the compiler thinks "look in A for a member function or member who can use operator()".
Then the compiler thinks, "Ok, two possibilities here, which one is being referred to? a() or a(int c = 0) with a default c=0. Not sure.
If you removed the static keyword and called the functions like obj.a(), there would still be an ambiguity.
WRT LLVM's parser
I would say that it does some extra work for you, which is not required by the standard, which would be to assume A::a() is static.

Nonstatic member as a default argument of a nonstatic member function [duplicate]

This question already has answers here:
How to use a member variable as a default argument in C++?
(4 answers)
Closed 1 year ago.
struct X
{
X():mem(42){}
void f(int param = mem) //ERROR
{
//do something
}
private:
int mem;
};
Can anyone give me just one reason as to why this is illegal in C++?! That is to say, I know that it is an error, I know what the error means, I just can't understand why would this be illegal!
Your code (simplified):
struct X
{
int mem;
void f(int param = mem); //ERROR
};
You want to use a non-static member data as default value for a parameter of a member function. The first question which comes to mind is this : which specific instance of the class the default value mem belongs to?
X x1 = {100}; //mem = 100
X x2 = {200}; //mem = 200
x1.f(); //param is 100 or 200? or something else?
Your answer might be 100 as f() is invoked on the object x1 which has mem = 100. If so, then it requires the implementation to implement f() as:
void f(X* this, int param = this->mem);
which in turn requires the first argument to be initialized first before initialization of other argument. But the C++ standard doesn't specify any initialization order of the function arguments. Hence that isn't allowed. Its for the same reason that C++ Standard doesn't allow even this:
int f(int a, int b = a); //§8.3.6/9
In fact, §8.3.6/9 explicitly says,
Default arguments are evaluated each
time the function is called. The order
of evaluation of function arguments is
unspecified. Consequently, parameters
of a function shall not be used in
default argument expressions, even if
they are not evaluated.
And rest of the section is an interesting read.
An interesting topic related to "default" arguments (not related to this topic though):
Default argument in the middle of parameter list?
Default arguments have to be known at compile-time. When you talk about something like a function invocation, then the function is known at compile-time, even if the return value isn't, so the compiler can generate that code, but when you default to a member variable, the compiler doesn't know where to find that instance at compile-time, meaning that it would effectively have to pass a parameter (this) to find mem. Notice that you can't do something like void func(int i, int f = g(i)); and the two are effectively the same restriction.
I also think that this restriction is silly. But then, C++ is full of silly restrictions.
As DeadMG has mentioned above, somethig like
void func(int i, int f = g(i))
is illegal for the same reason. i suppose, however, that it is not simply a silly restriction. To allow such a construction, we need to restrict evaluation order for function parameters (as we need to calculate this before this->mem), but the c++ standard explicitly declines any assumptions on the evaluation order.
The accepted answer in the duplicate question is why, but the standard also explicitly states why this is so:
8.3.6/9:
"
Example: the declaration of X::mem1() in the following example is ill-formed because no object is supplied for the nonstatic member X::a used as an initializer.
int b;
class X
int a;
int mem1(int i = a); // error: nonstatic member a
// used as default argument
int mem2(int i = b); // OK: use X::b
static int b;
};
The declaration of X::mem2() is meaningful, however, since no object is needed to access the static member X::b. Classes, objects and members are described in clause 9.
"
... and since there exists no syntax to supply the object necessary to resolve the value of X::a at that point, it's effectively impossible to use non-static member variables as initializers for default arguments.
ISO C++ section 8.3.6/9
a nonstatic member shall not be used in a default argument expression, even if it
is not evaluated, unless it appears as the id-expression of a class member access expression (5.2.5) or unless it is used to form a pointer to member (5.3.1).
Also check out the example given in that section.
For one reason, because f is public, but mem is private. As such, code like this:
int main() {
X x;
x.f();
return 0;
}
...would involve outside code retrieving X's private data.
Aside from that, it would (or at least could) also make code generation a bit tricky. Normally, if the compiler is going to use a default argument, it gets the value it's going to pass as part of the function declaration. Generating code to pass that value as a parameter is trivial. When you might be passing a member of an object (possibly nested arbitrarily deeply) and then add in things like the possibility of it being a dependent name in a template, that might (for example) name another object with a conversion to the correct target type, and you have a recipe for making code generation pretty difficult. I don't know for sure, but I suspect somebody thought about things like that, and decided it was better to stay conservative, and possibly open thins up later, if a good reason was found to do so. Given the number of times I've seen problems arise from it, I'd guess it'll stay the way it is for a long time, simply because it rarely causes problems.
Compiler has to know addresses to maintain default values at compile time. Addresses of non-static member variables are unknown at compile time.
As all the other answers just discuss the problem, I thought I would post a solution.
As used in other languages without default arguments (Eg C# pre 4.0)
Simply use overloading to provide the same result:
struct X
{
X():mem(42){}
void f(int param)
{
//do something
}
void f()
{
f(mem);
}
private:
int mem;
};
Default arguments are evaluated in two distinct steps, in different contexts.
First, the name lookup for the default argument is performed in the context of the declaration.
Secondly, the evaluation of the default argument is performed in the context of the actual function call.
To keep the implementation from becoming overly complicated, some restrictions are applied to the expressions that can be used as default arguments.
Variables with non-static lifetime can't be used, because they might not exist at the time of the call.
Non-static member variables can't be used, because they need an (implicit) this-> qualification, which can typically not be evaluated at the call site.

C++ Scoping and ambiguity in constructor overloads

I've tried the following code snippet in 3 different compilers (G++, clang++, CL.exe) and they all report to me that they cannot disambiguate the overloaded constructors. Now, I know how I could modify the call to the constructor to make it pick one or the other (either make explicit that the second argument is a unsigned literal value or explicitly cast it).
However, I'm curious why the compiler would be attempting to choose between constructors in the first place given that one of the constructors is private and the call to the constructor is happening in the main function which should be outside the class's scope.
Can anyone enlighten me?
class Test
{
private:
Test(unsigned int a, unsigned int *b) { }
public:
Test(unsigned int a, unsigned int b) { }
};
int main()
{
Test t1 = Test(1,0); // compiler is confused
}
In C++, accessibility to class members doesn't influence the other language semantics. Instead, any invalid access causes a program to be ill-formed.
In other words, there is accessibility and visibility. The Standard has it straight
It should be noted that it is access to members and base classes that is controlled, not their visibility. Names of members are still visible, and implicit conversions to base classes are still considered, when those members and base classes are inaccessible. The interpretation of a given construct is established without regard to access control. If the interpretation established makes use of inaccessible member names or base classes, the construct is ill-formed.
The compiler does not attempt to select an overloaded function or constructor by its visibility.
It is more that the compiler will not refuse a candidate function even if it is marked as private. This means changing visability of a member will not changing existing code.
As for your second question, overload resolution happens before the test for visibility.
As for the first, you need to indicate to the compiler that the 0 is an unsigned int. As far as the compiler is concerned, the conversion from integer 0 to unsigned int is no better than the conversion from integer 0 to pointer.