The following question is part of the C++ Test on Upwork.
class A {
typedef int I; // private member
I f();
friend I g(I);
static I x;
};
which of the following are valid:
1) A::I A::f() { return 0; }
2) A::I g(A::I p = A::x);
3) A::I g(A::I p) { return 0; }
4) A::I A::x = 0;
Seems to me that all answers are valid. I tested them and they work just fine!
Am I right? or Am I missing something?
The way it's written, all 4 are valid.
This is trivial; it's the definition of the class member function.
This is a function prototype for a function g. Requires the friend declaration, which you have. Otherwise neither I nor the default value x are accessible to the function g.
This is the definition of the function g. Requires the friend declaration, which you have, else I is not accessible to the function g.
This is trivial; it's the definition of the static member x.
Related
At https://www.studytonight.com/cpp/inline-functions.php they are explaining inline functions
All the inline functions are evaluated by the compiler, at the end of class declaration.
class ForwardReference
{
int i;
public:
// call to undeclared function
int f()
{
return g()+10;
}
int g()
{
return i;
}
};
int main()
{
ForwardReference fr;
fr.f();
}
At the end they say :
"You must be thinking that this will lead to compile time error, but in this case it will work, because no inline function in a class is evaluated until the closing braces of class declaration."
......
why should one expect a compile time error? is it because no value for i has been set? If so, could someone explain better why it works, I don't get what's the point here, if the member functions are inline or not wouldn't it work the same?
The book is explicitly pointing out to you "no inline function in a class is evaluated until the closing braces of class declaration". Outside of a class declaration, with ordinary functions, this fails:
int f()
{
return g()+10;
}
int g()
{
return 0;
}
Try to compile a C++ source file containing just this, and nothing more, and see for yourself.
In C++, all functions must be declared before use. Since g() is not declared, this is ill-formed and your compiler will reject it. g() must be declared before it's referenced:
int g();
int f()
{
return g()+10;
}
int g()
{
return 0;
}
This does not applly to inline class method because, as your book explains, they are effectively evaluated when the class declaration is complete. At that point both f() and g() methods are declared, and the reference from f() to g() is well-formed.
What they are hinting at here, for why someone might expect a compile error, is the fact that although g is written below/after f, f can still reference it with no error.
If you were to move them out of the class and define+declare them at the same time then you would see the compile error (since f cannot see any g).
i.e.
int f(){
return g() + 10;
}
int g(){
return 32;
}
int main(){
return f();
}
See for yourself on compiler explorer.
I have a class for a tree as shown below:
class avl
{
node *root;
public:
avl(int data){
root->data = data;
}
int get_height(node *head = root){ //error here
if (head->right == head->left) return 0;
int l = get_height(head->left);
int r = get_height(head->right);
if (l > r) return l+1;
return r+1;
}
}
Unsurprisingly this generates an error at the get_height definition. g++ complains it as an "invalid use of non-static data member". Can I amend this issue or should I resort to an inelegant use of a wrapper here. I'd appreciate if you can add some details to what the standard says about the cause of this error.
Unfortunately this is impossible. Non-static class members can't be used as default arguments.
Non-static class members are not allowed in default arguments (even if
they are not evaluated), except when used to form a pointer-to-member
or in a member access expression.
int b;
class X {
int a;
int mem1(int i = a); // error: non-static member cannot be used
int mem2(int i = b); // OK: lookup finds X::b, the static member
static int b;
};
From the standard, [dcl.fct.default]/9
A non-static member shall not appear in a default argument unless it
appears as the id-expression of a class member access expression
([expr.ref]) or unless it is used to form a pointer to member
([expr.unary.op]). [ Example: The declaration of X::mem1() in the
following example is ill-formed because no object is supplied for the
non-static member X::a used as an initializer.
int b;
class X {
int a;
int mem1(int i = a); // error: non-static 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 [class]. — end example ]
As you said you can add an overloaded wrapper function like
int get_height(node *head) {
...
}
int get_height() {
return get_height(this->root);
}
I was watching one of Jason Turner's videos and I saw that you can define a type inside a function scope and have it available outside of that scope through function return type deduction.
auto f()
{
struct MyStruct
{
int n;
};
return MyStruct{};
}
int main()
{
auto a = f().n;
return a;
}
Why is this allowed? Is there a paragraph in the C++ 14 standard that allows this?
When trying to get the typeid of MyStruct with clang in compile explorer I saw in the assembly output the type displayed as f()::MyStruct, so there is a scope, but somehow I can access MyStruct outside of that scope. Is this some kind of ADL thing?
No, there's no ADL involved. Since your translation unit contains the definition of the structure, there's no problem in accessing its members.
The important point is that types don't really exist in scopes: names do. And notice that there's no way for you to use the identifier MyStruct instead of auto when declaring a. The name is as inaccessible as it should be. However, as long as you can get at the type without using the inaccessible name, all is fine.
In principle, this is hardly different from using a private member type:
class X
{
struct Hidden
{
int i;
};
public:
Hidden get() const { return {42}; }
};
int main()
{
X x;
auto h = x.get();
assert(h.i == 42);
}
I see this code and I can't understand what it mean.
I know how we use default constructor but this is not default constructor. What is this?
class X
{
...
};
int main()
{
X f();
}
It declares a function f which takes no parameters and returns a type X.
This is also known as Most Vexing Parse in C++. It is a byproduct of the way the C++ standard defines the interpretation rules for declarations.
Assume you declare a function:
int Random();
And use it:
int main()
{
int n;
n = Random();
}
But implement the Random function after main. Or assume that Random function is defined in some header. You need to instruct the compiler that Random is a function implemented in some other source file, or in some library.
Therefore, an expression like:
T foo();
Would always mean a instruction to compiler that there is a function named foo which returns T. It cannot be an object of type T.
Its function declaration of name f
X f();
^ ^ function
return type
function f() takes no arguments and returns a X class object.
for example its definition can be like:
class X{
int i;
// other definition
}
X f(){
X x;
// some more code
return x;
}
In main you can use like:
int main(){
X a = f();
int i = f().i;
}
This is a function which doesn't take any argument and returns an object of class X
Why should this be an error?
int a = 0;
a = 42;
int main()
{
}
A possibe match for this behavior i could find:
(3.4.1/4) A name used in global scope, outside of any function, class
or user-declared namespace, shall be declared before its use in global
scope.
Could this be a defect in standard?
int a = 0; //it is a declaration (and definition too) statement
a = 42; //it is an assignment statement
The second line is the cause of error, for it is an assignment statement.
At the namespace-level, only declaration and definition statements are allowed. Assignment-statements are not allowed at namespace level.
And by "shall be declared before its use in global scope" (from the spec's quotation) means the following:
int a = 42;
int b = 2 * a; //a is being used here
int c = a + b; //both a and b are being used here
If you define type instead, then:
struct A {}; //definition of A
struct B { A a; }; //a is declared as member of B
//(which means, A is being "used")
void f(const A&, const B&); //both A and B are used in the declaration of f
You cannot write an assignment statement like that in the global namespace
it needs to be either in main or in some [member] function
int main()
{
a=42;
return 0;
}