typecast operator in private base - c++

I found something I consider strange behaviour in C++: a typecast operator in a private base class is confusing the compiler when trying to resolve an implicit cast:
#include <iostream>
struct Base
{
#ifdef ENABLE
operator bool () const { return true; }
#endif
};
struct Derived : private Base
{
operator int () const { return 7; }
};
int main()
{
Derived o;
std::cout << o << '\n';
return 0;
}
Without -DENABLE, the code compiles just fine, and outputs 7. With -DENABLE, the code no longer compiles, complaining about an ambiguous overload. I tried gcc-4.6.5, gcc-4.8.1, and clang-3.3. What's confusing is that I clearly cannot ask for (bool)o, because Base is a private base.
Is this expected behaviour?

Access control always comes last. Quote from the Standard:
10.2 Member name lookup [class.member.lookup]
1 Member name lookup determines the meaning of a name (id-expression)
in a class scope (3.3.7). Name lookup can result in an ambiguity, in
which case the program is ill-formed. For an id-expression, name
lookup begins in the class scope of this; for a qualified-id, name
lookup begins in the scope of the nestedname- specifier. Name lookup
takes place before access control (3.4, Clause 11).
8 If the name of an overloaded function is unambiguously found,
overloading resolution (13.3) also takes place before access control.
Ambiguities can often be resolved by qualifying a name with its class
name.
The reason both operators are considered is that a) the base clas conversion is not hidden by the derived one (which it would if both had been converting to the same type), b) both bool and int can be written to stdout, c) neither is a better match than the other so overload resolution yields an ambiguity. This yields a hard error even before access control comes into play.

Related

Does member function like operator<< , operator* need ADL to work?

I have a code snippet (Hypothetically):
#include <iostream>
struct Pirate {
void song_name() {
std::cout << "Bink's Sake\n";
}
Pirate& operator*(Pirate const& other) {
// do something
return *this;
}
};
int main() {
Pirate p1{} p2{};
p1.song_name(); // does this use qualified or unqualifed name lookup?
p1 * p2;
std::cout << 5;
std::cout << 'a';
}
Does p1 * p2 use qualified name lookup or unqualified name lookup or ADL?
std::cout << 5 transforms into std::cout.operator<<(5);
std::cout << 'a' transforms into std::operator<<(std::cout, 'a');
Does member functions require ADL to work?
Does the above two statments use qualified or unqualifed name lookup or ADL?
Thanks
The operators lookup non-static member functions like
std::cout.operator<<(5);
but also non-member functions via unqualified lookup and ADL if they have a non-member variant. All of these together form the overload set.
For this to work correctly non-member variants should be found via ADL, i.e. placed inside the namespace of the class for which they are overloading the operator. E.g. for overloading operator<< for your own classes you cannot use a member version, because the first argument is probably supposed to be anything derived from std::ostream. Then ADL on the non-member variant is the only way to make it work everywhere.
A name is a qualified name if the scope to which it belongs is explicitly denoted using a scope-resolution operator (::) or a member access operator (. or ->).
Case 1
Thus, when you wrote:
p1.song_name(); //here p1.song_name is a qualified name
In the above statement, p1.song_name is a qualified name and so here qualified lookup takes place.
Case 2
Next, when your wrote:
p1 * p2;
The above statement is equivalent to:
p1.operator*(p2);
Since your class Pirate have an overloaded member function operator*, the above statement will use that member function. The above statement uses qualified lookup as well because we have used the member access operator ..
Case 3
Here we have the statement:
std::cout << 5;
The above statement is equivalent to:
std::cout.operator<<(5);
which uses qualified lookup since it has member access operator .
Case 4
Here we look at the statement:
operator<<(std::cout, 'a');
Here the char overload from operator<< for ofstream is used. This uses ADL because in this case the first parameter has a class type. So the compiler will also look in the namespace in which cout is defined. Thus, for this call, the compiler also looks in the std namespace and finds the char overload.

confusion about C++ name lookup

According to my knowledge, the name in a nested scope will hide the same name in the enclosing scope, just like what shows below:
namespace ttt {
class A {};
void test(const A&, int)
{
cout << "ttt::test()" << endl;
}
}
void test(const ttt::A&, int)
{
cout << "global::test()" << endl;
}
int main()
{
void test(const ttt::A&, int);
ttt::A a;
test(a, 1);
}
the declaration of void test(const ttt::A&, int); in the main function hides the same name which is in the namespace ttt, so the console prints global::test()(Tested in Visual Studio 2019)
However, when I try the code below:
std::ostream& operator<< (std::ostream& os, const string& str)
{
os << "global::operator" << endl;
return os;
}
int main()
{
std::ostream& operator<< (std::ostream & os, const string & str);
string a = "STD's operator";
cout << a << "STD's operator" << endl;
}
I try to overload the << operator which is a template defined in STL with my own version of <<. According to the first example, the declaration of operator<< in main should hide the STL defined version of <<, then the desired output should be
global::operator
global::operator
global::operator
or a compile error, since I don't know whether endl can be converted to string.
however, the result of the program is:
global::operator
STD's operator
So the second and the last << in the statement cout << a << "STD's operator" << endl; invokes the STL's <<, not the overloaded one define by me. Shouldn't the << already be hidden by the declaration std::ostream& operator<< (std::ostream & os, const string & str); in main ?
Someone may say "STD's operator" is const char*, so that the Argument Dependent Lookup(ADL) adds a better candidate which is std::ostream& operator<< (std::ostream&, const char*) from std namespace. If this is true, then how to explain the first example. The ADL procedure in the first example may add ttt::test(const A&, int) into overloading candidate and that would cause ambiguity in the first example, but that didn't happen, the ttt::test(const A&, int) just been hidden.
Page 798 of "C++ primer 5th" says that "When we pass an object of a class type to a function, the compiler searches the namespace in which the argument’s class is defined in addition to the normal scope lookup". I think my confusion is about the accurate meaning of in addition to.
If it means that the class's namespace has the same precedence of the scope where the function is called, then the first example should cause ambiguity.
If it means that the class's namespace has lower precedence, then all the << in the main function in the second example should be hidden by the version defined by me.
If it means that the class's namespace has higher precedence, then the first example should print "ttt::test()".
So what happened?
ADL is not performed if one of the candidate functions is declared at block scope, like your block scope function declarations. (When ADL is performed, it indeed has no special preferential treatment when picking the most viable candidate)
So your first example, void test(const ttt::A&, int); (which is a block scope declaration for ::test), means that ttt::test is no longer a candidate, and the global ::test is called (removing the block scope declaration makes it ambiguous)
I believe that you are correct here and the second example should call your global operator after constructing a std::string.
Compilers seem to agree that std::cout << a << "STD's operator" << std::endl compiles to the equivalent of std::operator<<(::operator<<(std::cout, a), "STD's operator").operator<<(std::endl). The << std::endl is fine since it's found by member lookup instead of ADL. The problem is that ADL is still used to find std::operator<<(std::ostream&, const char*)
Reading directly from the C++11 standard on what should happen:
"Operators in expressions" [over.match.oper]p2:
If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator [...]. In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator. Therefore, the operator notation is first transformed to the equivalent function-call notation as summarized in Table 11 (where # denotes one of the operators covered in the specified subclasses)
Both operands are of class types, so user-defined operator functions are considered as expected. The relevant subclause of table 11 is 13.5.2, with the expression a#b, which is (a).operator#(b) as a member function and operator#(a, b) as a non-member function.
[over.match.oper]p3
[...] for a binary operator # with a left operand of type cv1 T1 and a right operand of type cv2 T2, three sets of candidate functions, designated member candidates, non-member candidates and built-in candidates, are constructed as follows:
[...]
The set of non-member candidates is the result of the unqualified lookup of operator# in the context of the expression according to the usual lookup in unqualified function calls (3.4.2) except that all member functions are ignored.
Where §3.4.2 is [basic.lookup.arg] "Argument-dependent name lookup".
[basic.lookup.arg]p3 says:
Let X be the lookup set produced by unqualified lookup (3.4.1) and let Y be the lookup set produced by argument dependent lookup (defined as follows). If X contains
a declaration of a class member, or
a block-scope declaration that is not a using-declaration, or
a declaration that is neither a function or a function template
then Y is empty. [...] The set of declarations found by the lookup of the name is the union of X and Y.
Looking only at std::cout << "STD's operator" for simplicity, the name looked up is operator<<. The unqualified lookup finds the block scope declaration for std::ostream& operator<< (std::ostream & os, const string & str); only (and all other declarations are hidden). But since the function declaration in a block scope was found, ADL shouldn't happen and there are no further non-member candidates.
Thus the set of candidate functions is only the global ::operator<<(std::ostream & os, const string &) and the member operator<< in std::ostream and its base classes, of which the global function is the most viable.
Compilers seem to ignore this rule when looking up operators, always performing ADL even if there is a block scope declaration. Writing operator<<(std::cout, "STD's operator") does it correctly and outputs global::operator.
Only in addition to #Artyer's answer.
In practice, you shouldn't ever provide a different definition of std:: functions in a different namespace because the call may accidentally go into a std:: version, with no warning or error.
The robust solution is to name your functions differently or wrap you arguments in a different class object, so that you never accidentally call a std:: function when you don't intend to.
For example, if you want a version of std::isnan that works correctly with -ffast-math, call it isnan2, not isnan which might resolve into std::isnan.
A part of being a good software engineer is preventing potential problems for yourself in the future. And avoiding name clashes with std:: functions which may be found via ADL is robust engineering - a philosophy or way of thinking about engineering that makes accidental semantic changes of existing correctly working code impossible.
In your example, there is no need or justification for creating another version of std::operator<< in another namespace. But there are undesirable problems which arise from from such a decision. In other words, the reward is 0, but the risk is infinite.

Cannot declare an operator within a function. Clang bug or spec?

One of the weirder corner cases of C is that functions can be declared within other functions, e.g.
void foo(void)
{
void bar(void); // Behaves as if this was written above void foo(void)
bar();
}
This has carried through into C++, at least for most functions. Clang doesn't appear to recognise the pattern if the function in question happens to be called operator==.
struct foo
{
int value;
};
struct bar
{
foo value;
};
bool wot(const bar &x, const bar &y)
{
bool eq(const foo &, const foo &); // Declare function eq
bool operator==(const foo &, const foo &); // Declare function operator==
bool func = eq(x.value, y.value); // This line compiles fine
bool call = operator==(x.value, y.value); // Also OK - thanks user657267!
bool op = x.value == y.value; // This one doesn't
return func && call && op;
}
bool test()
{
bar a;
bar b;
return wot(a,b);
}
GCC and ICC compile this fine. Checking name mangling in the object suggests the operator== has been declared with the right types. Clang (I tried up to 3.8) errors:
error: invalid operands to binary expression
('const foo' and 'const foo')
bool op = x.value == y.value;
~~~~~~~ ^ ~~~~~~~
Unless the declaration is moved to directly above the function, in which case Clang is happy too:
bool operator==(const foo &, const foo &);
bool wot(const bar &x, const bar &y)
{
return x.value == y.value; // fine
}
I can't use this workaround as the "real world" case that provoked this question involves layers of templates, meaning I only know the type name "foo" within the function declaration.
I believe this is a bug in Clang - is there special handling of operatorX free functions which prohibits declaring them within a function?
For overloaded operators, see [over.match.oper]/(3.2):
[…] for a binary operator # with a left operand of a type whose cv-unqualified version is T1 and a right operand of a type whose
cv-unqualified version is T2, […] non-member
candidates […] are constructed as follows:
The set of non-member candidates is the result of the unqualified
lookup of operator# in the context of the expression according to the
usual rules for name lookup in unqualified function calls (3.4.2)
except that all member functions are ignored. However, if no operand
has a class type, […]
That is, we have the exact same name lookup rules as in ordinary calls, because x.value is of class type (foo). It's a Clang bug, and it occurs with all binary operators. Filed as #27027.
It is true that C allows functions to be declared inside functions: 6.7.5.3 Function declarators §17 (draft n1256 for C99) says (emphasize mine)
If the declaration occurs outside of any function, the identifiers have file scope and external linkage. If the
declaration occurs inside a function, the identifiers of the functions f and fip have block scope and either
internal or external linkage (depending on what file scope declarations for these identifiers are visible), and
the identifier of the pointer pfi has block scope and no linkage.
C++ also allows them. Draft n4296 for C++ 14 says:
13.2 Declaration matching [over.dcl] ...
2 A locally declared function is not in the same scope as a function in a containing scope. [ Example:
void f(const char*);
void g() {
extern void f(int);
...
(the above quote is only here to have an explicit evidence that C++ allows function declarations inside function)
I could even test that with your example this line:
bool op2 = operator == (x.value, y.value);
compiles fine without a single warning and gives expected results.
So I would say that it is a bug in Clang

Unrelated deleted operator changes behaviour of overload resolution

I came across a strange situation today, where declaring a deleted operator with certain arguments changed the behaviour of seemingly unrelated code.
I reduced it to the following. Start with this:
namespace N
{
enum E { A, B };
struct C
{
C(E);
private:
C(int);
};
}
N::E operator|(N::E, N::E);
namespace N
{
void Waldo()
{
C(A | B);
}
}
Notice that C has two constructors, a public one and a private one. This code compiles, indicating that the public overload is being chosen, so the expression A | B has type E. In turn this means that the operator|(N::E, N::E) has been matched (otherwise A and B would undergo implicit conversion to integers, the type of A | B would be int, and the private constructor would be matched.
So far so good. Now I define a new enumeration type F, and a deleted operator| that involves F:
namespace N
{
enum E { A, B };
struct C
{
C(E);
private:
C(int);
};
}
N::E operator|(N::E, N::E);
namespace N
{
enum F {};
int operator|(F, int) = delete;
void Waldo()
{
C(A | B);
}
}
Now the code doesn't compile, saying that C(int) is private. This indicates that now A | B has type int, which means operator|(N::E, N::E) is no longer being matched.
Why did the addition of the deleted operator|(F, int) stop operator|(N::E, N::E) from being matched?
First off, note that being declared as deleted is irrelevant, since deleted functions still take part in overload resolution.
Now, on to overload resolution. Cf. 13.3.1.2/3:
three sets of candidate functions, designated member candidates, nonmember
candidates and built-in candidates, are constructed
(There are no member candidates, since E is not a class type.) We know from that the operator overload is found by unqualified lookup. So when we consult 3.4.1 ("Unqualified lookup"), we find that
name lookup ends as soon as a declaration is found for the name.
Since you introduce the second operator overload within the namespace N, it is found first, and name lookup stops. At this point, the overload set consists of your int N::operator|(N::F, int) and the built-in operators. Continuing in 13.3.1.2/6:
The set of candidate functions for overload resolution is the union of the member candidates, the non-member candidates, and the built-in candidates.
Only the builtin is viable (since you cannot convert E to F implicitly), and thus it is chosen.
The solution to your problem is simple.
Put your operator| in the same namespace as the type. Now, ADL (argument dependent lookup) kicks in, and it is found even if there is the unrelated operator| also visible.
Live example. Note that N::operator| is found despite the | being used in namespace Z.
The proper place to overload free operators for a type is the namespace that the type lives in, not the global namespace.

How is this possible to use in c++?

To my surprise, I found that the name of a c++ object can be the same as class name. Can someone explain to me the reason why?
When I declare an object of class a as a a1(), it does not raise an error, but doesn't call the constructor. Why is this happening?
My code:
#include<iostream>
using namespace std;
class a
{
public:
a()
{
cout << "in a\n";
}
};
int main()
{
a a1();
a a;
}
When you write a a1(); it is actually being parsed as a function declaration not a call to the default constructor.
a a1;
will call the default constructor correctly
When you write a a; it works because the variable name takes preference over the class name in what is called name hiding, but even though it works it will only lead to confusion and I would avoid doing it.
And for all those people who like standards quotes here you go
A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.
a a1(); is a function declaration.
That's an important reason for the creation of uniform initialization in C++11. To initialize the object using the constructor in C++11, use a a1{};
It is valid to hide the name of a class with a variable in fact if you look at the C++draft standard section 3.3.10 Name hiding paragraph 2 says(emphasis mine):
A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is
visible.
I don't think it is good practice and it would lead to hard to maintain code. This line of code is actually declaring a function:
a a1();
you can alternatively use this pre-C++11:
a a1 ;
or uniform initialization introduced in C++11 :
a a1{} ;
Circling back to name hiding, I was pleasantly surprised to see that clang will warn you about this with this code regardless of the warning levels set:
int main()
{
a a;
a a2 ;
}
I receive this message:
main.cpp:12:10: note: class 'a' is hidden by a non-type declaration of 'a' here
a a;
^
although I can't see to obtain a similar warning from gcc.
Update
Thinking about this comments I made earlier on warts of uniform initialization, I realized that had you suspected that a1 was somehow not the correct type you could have have used typeid to debug what was going on. For example this code:
std::cout << typeid(a).name() << std::endl ;
std::cout << typeid(a1).name() << std::endl ;
results in this output on Coliru live example:
1a
F1avE
and passing it through c++filt you receive this output:
a () // A function that returns type a
a // type a
a a1(); is a function declaration return type as a which has nothing to do with the calling constructor
a a ; is simple statement works fine will call the constructor
This is what I got from your code when tried to compile it with clang, I think it says everything.
test.cpp:15:9: warning: empty parentheses interpreted as a function declaration
[-Wvexing-parse]
a a1();
^~
test.cpp:15:9: note: remove parentheses to declare a variable
a a1();
^~
1 warning generated.