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
Related
I have come across this code snippet and have no idea what it means:
#include <iostream>
int main(){
using test = int(int a, int b);
return 0;
}
I can guess test can be used instead of int(int a, int b), but what does int(int a, int b) even mean? is it a function? How can it be used?
int(int a, int b) is a function declaration that has two parameters of the type int and the return type also int.
You can use this alias declaration for example as a member function declarations of a class or using it in a parameter declaration.
It's an alias for a function signature.
A more complete usage is to declare a pointer or reference to a function
int foo(int, int);
int main()
{
using test = int(int a, int b); // identifiers a and b are optional
test *fp = &foo;
test *fp2 = foo; // since the name of function is implicitly converted to a pointer
test &fr = foo;
test foo; // another declaration of foo, local to the function
fp(1,2); // will call foo(1,2)
fp2(3,4); // will call foo(3,4)
fr(5,6); // will call foo(5,6)
foo(7,8);
}
Just to give another use option of this line, with lambda expressions:
int main() {
using test = int(int, int);
test le = [](int a, int b) -> int {
return a + b;
}
return 0;
}
One point that you have to keep in mind about this use of test, there are probably more efficient ways to declare a function signature, like auto in lambda expressions case, template in case of passing function as argument to another function, etc.
This way came all the way from pure C programming, with the using twist. I won't recommend of choosing this way, but for general understanding it is always good to know more than the correct ways.
Is there a nice way to have a non static value as default argument in a function? I've seen some older responses to the same question which always end up in explicitly writing out the overload. Is this still necessary in C++17?
What I'd like to do is do something akin to
class C {
const int N; //Initialized in constructor
void foo(int x = this->N){
//do something
}
}
instead of having to write
class C {
const int N; //Initialized in constructor
void foo(){
foo(N);
}
void foo(int x){
//do something
}
}
which makes the purpose of the overload less obvious.
One relatively elegant way (in my opinion) would be to use std::optional to accept the argument, and if no argument was provided, use the default from the object:
class C {
const int N_; // Initialized in constructor
public:
C(int x) :N_(x) {}
void foo(std::optional<int> x = std::nullopt) {
std::cout << x.value_or(N_) << std::endl;
}
};
int main() {
C c(7);
c.foo();
c.foo(0);
}
You can find the full explanation of what works/doesn't work in section 11.3.6 of the standard. Subsection 9 describes member access (excerpt):
A non-static member shall not appear in a default argument unless it
appears as the id-expressionof a class member access expression
(8.5.1.5) or unless it is used to form a pointer to member
(8.5.2.1).[Example:The declaration of X::mem1()in the following example
is ill-formed because no object is supplied for the non-static
memberX::a used as an initializer.
int b;
class X {
int a;
int mem1(int i = a);// error: non-static memberaused as default argument
int mem2(int i = b);// OK; useX::b
static int b;
};
For example, there is a class foo :
class foo {
public:
foo (int = 10);
.....
}
The prototype of the constructor has "int = 10" inside. So, what does it mean? Int is just an integer type, isn't? So, isn't that illegal to assign a value to it? I was trying to find such an example in Prata's book, and everywhere else, but I didn't find the explanation.
You can omit the name of parameter in function declaration (in definition too), but still you are able to specify default value of that parameter.
Consider:
void f(int x = 10) {
printf("%d\n", x);
}
void g(int = 10);
void g(int x) {
printf("%d\n", x);
}
int main() {
f();
g();
return 0;
}
Result:
10
10
The same situation is in the constructor case.
So, isn't that illegal to assign a value to it?
There is absolutely no assignment involved here. The = character can have quite different meanings in C++:
Assignment: i = 0;
Initialisation: int i = 0;
Making a member function pure virtual: virtual void f() = 0;
Specifiying default arguments: void f(int i = 0);
The latter is what you have encountered. A constructor can have default arguments like any other normal function.
In standard Section ยง6.8 of the Standard (N3690 draft) I see this weird piece of code :
struct T2 { T2(int){ } };
int a, (*(*b)(T2))(int), c, d;
What is int(*(*b)(T2))(int) ?!
Is b a pointer to T2's constructor ?! or maybe a pointer to function pointer ?
It's weird that the bellow code also compile fine !:
struct T2 { T2(int){ } };
int((*b)(T2));
int (*(*b)(T2))(int)
It declares b as pointer to a function which:
takes T2 as argument
and returns pointer to a function which
takes an int as argument
and returns an int.
One should simplify this declaration using typedefs as:
typedef int (*return_type) (int);
typedef return_type(*function_type) (T2);
Or better use C++11 style type aliases:
using return_type = int(*)(int);
using function_type = return_type(*)(T2);
Then the declaration becomes this:
function_type b; //so simple!
Hope that helps.
It is declaration of variable b. b is a pointer to function with one parameter of type T2. The return type of this function is pointer to function with one parameter int returning int.
This should help you understand what is going on here:
struct T2 { T2(int){ } };
typedef int (*func)(int);
int
(*foo(T2))(int) {
}
func
bar(T2) {
}
int main() {
int (*(*b)(T2))(int);
b = &foo;
b = &bar;
return 0;
}
So this is a function that take a T2 and return a function pointer to a function that return an int and take an int as parameter.
I a add this to my example of why c(++) is an horrible language.
By the way, you cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")
After getting an answer to this question I discovered there are two valid ways to typedef a function pointer.
typedef void (Function) ();
typedef void (*PFunction) ();
void foo () {}
Function * p = foo;
PFunction q = foo;
I now prefer Function * p to PFunction q but apparently this doesn't work for pointer-to-member functions. Consider this contrived example.
#include <iostream>
struct Base {
typedef void (Base :: *Callback) ();
//^^^ remove this '*' and put it below (i.e. *cb)
Callback cb;
void go () {
(this->*cb) ();
}
virtual void x () = 0;
Base () {
cb = &Base::x;
}
};
struct D1 : public Base {
void x () {
std :: cout << "D1\n";
}
};
struct D2 : public Base {
void x () {
std :: cout << "D2\n";
}
};
int main () {
D1 d1;
D2 d2;
d1 .go ();
d2 .go ();
}
But if I change it to the new preferred style: typedef void (Base :: Callback) () and Callback * cb, I get a compiler error at the point of typedef
extra qualification 'Base::' on member 'Callback'
Demo for error.
Why is this not allowed? Is it simply an oversight or would it cause problems?
For non-member functions, a type such as typedef void(Function)() has several uses, but for member functions the only application is to declare a variable which holds a function pointer. Hence, other than a stylistic preference, there's no strict need to allow this syntax and it has been omitted from the standard.
Background
The :: is a scope resolution operator, and the syntax X::Y is reserved for static member access if X is a class type. So X::*Z was another syntax invented to define pointer-to-member.
Forget member-function for a while, just think about member-data, and see this code:
struct X
{
int a;
};
int X::*pa = &X::a; //pointer-to-member
X x = {100}; //a = 100
cout << (x.*pa) << endl;
It defines a pointer-to-member-data, and the cout uses it to print the value of a of object x, and it prints:
100
Demo : http://www.ideone.com/De2H1
Now think, if X::pa (as opposed to X::*pa) were allowed to do that, then you've written the above as:
int X::pa = X::a; //not &X::a
Seeing this syntax, how would you tell if X::a is a static member or non-static member? That is one reason why the Standard came up with pointer-to-member syntax, and uniformly applies it to non-static member-data as well as non-static member-function.
In fact, you cannot write X::a, you've to write &X::a. The syntax X::a would result in compilation error (see this).
Now extend this argument of member-data to member-function. Suppose you've a typedef defined as:
typedef void fun();
then what do you think the following code does?
struct X
{
fun a;
};
Well, it defines member a of type fun (which is function taking no argument, and returning void), and is equivalent to this:
struct X
{
void a();
};
Surprised? Read on.
struct X
{
fun a; //equivalent to this: void a();
};
void X::a() //yes, you can do this!
{
cout << "haha" << endl;
}
We can use exactly the same syntax to refer to a which is now a member-function:
X x;
x.a(); //normal function call
void (X::*pa)() = &X::a; //pointer-to-member
(x.*pa)(); //using pointer-to-member
The similarity is the synatax on the right hand side : &X::a. Whether a refers to a member-function or member-data, the syntax is same.
Demo : http://www.ideone.com/Y80Mf
Conclusion:
As we know that we cannot write X::a on the RHS, no matter if a is a member-data or member-function. The only syntax which is allowed is &X::f which makes it necessary that the target type (on LHS) must be pointer as well, which in turn makes the syntax void (X::*pa)() absolutely necessary and fundamental, as it fits in with other syntax in the language.
To be precise the two typedef's in the case of the non-member pointers are not the same:
typedef void function();
typedef void (*fptr)();
The first defines function as a function taking no arguments and returning void, while the second defines ftpr as a pointer to function taking no arguments and returning void. The confusion probably arises as the function type will be implicitly converted to a pointer type in many contexts. But not all:
function f; // declares void f();
struct test {
function f; // declares void test::f()
};
void g( function f ); // declares g( void (*f)() ): function decays to pointer to function in declaration
g( f ); // calls g( &f ): function decays to pointer to function
void f() {} // definition of f
// function h = f; // error: cannot assign functions
function *h = f; // f decays to &f
Let's skip the "function" part for a second. In C++, we have the int, the int* and the int Foo::* types. That's a regular integer, pointer to integer, and a pointer to an integer member. There is no fourth type "integer member".
Exactly the same applies to functions: there's just no type "member function", even though there are function types, function pointer types, and member function pointer types.