My Attempt At Value Initialization Is Interpreted as a Function Declaration, and Why Doesn't a A(()); Solve It

I do not understand why this compiles

It's interpreted as the declaration of a function named a, which takes one argument of type B and returns A.

Passing instances of objects in C++ class constructors (could not compile) [duplicate]

A aa(B()); is a function declaration. So you cannot write aa.foo() because you cannot use . on a function.

The rule is (approximately) that if code could be parsed as either a function declaration or an object definition, then it is parsed as a function declaration.

Instead you could use A aa{ B() }; which cannot be a function declaration.

Also see this thread

I'm getting 3 C4703 errors on variables I think I've initialized correctly and I'm not sure what I'm missing

You should initialize all of the member of your SubExpression class, and not have them in an inconsistent, uninitialized state.

Here is what initialization should look like:

class SubExpression : public Expression
{
public:
SubExpression(Expression* left, Expression* right);
SubExpression(Expression* left);
SubExpression(Expression* first, Expression* second, Expression* third);
static Expression* parse(stringstream& in);

protected:
Expression* left;
Expression* right;
Expression* first;
Expression* second;
Expression* third;
};

SubExpression::Subexpression(Expression* left_, Expression* right_) : left(left_), right(right_), first(nullptr), second(nullptr), third(nullptr)
{}

SubExpression::Subexpression(Expression* left_) : left(left_), right(nullptr), first(nullptr), second(nullptr), third(nullptr)
{}

SubExpression::Subexpression(Expression* first_, Expression* second_, Expression* third_) : left(nullptr), right(nullptr), first(first_), second(second_), third(third_)
{}

Second, due to the pointers not being initialized, you will have a much harder time debugging a program that uses one of those uninitialized values. If at the very least, the pointer is set to nullptr, you have a better chance of fixing any errors.


Another potential reason for the warning is this code in the parse function:

Expression* left;
Expression* right;
Expression* first;
Expression* second;
Expression* third;

In the parse function, you are relying on the if() statement to be true to set the pointers above. Don't do that -- the same thing applies here that applies to your class members -- initialize all of those variables to nullptr.

Syntax of an un-named function pointer in C++

Fully explicit form:

Foo bar(Baz f());

bar is a function that takes a single parameter f, which is a function (taking no arguments) returning Baz.

Without naming the parameter:

Foo bar(Baz ());

The reason bar ends up taking a pointer to a function is that functions cannot be passed by value, so declaring a parameter as a function automatically decays it into a pointer. The above declaration is equivalent to:

Foo bar(Baz (*)());

// or:
Foo bar(Baz (*f)()); // with a named parameter

This is similar to void foo(int [10]) where int [10] also means int * in a parameter list.

Error initializer element is not constant when trying to initialize variable with const

In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.

A "large" object is never a constant expression in C, even if the object is declared as const.

Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.

For example, this is NOT a constant

const int N = 5; /* `N` is not a constant in C */

The above N would be a constant in C++, but it is not a constant in C. So, if you try doing

static int j = N; /* ERROR */

you will get the same error: an attempt to initialize a static object with a non-constant.

This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.

Proper way to initialize C++ structs

In C++ classes/structs are identical (in terms of initialization).

A non POD struct may as well have a constructor so it can initialize members.

If your struct is a POD then you can use an initializer.

struct C
{
int x;
int y;
};

C c = {0}; // Zero initialize POD

Alternatively you can use the default constructor.

C  c = C();      // Zero initialize using default constructor
C c{}; // Latest versions accept this syntax.
C* c = new C(); // Zero initialize a dynamically allocated object.

// Note the difference between the above and the initialize version of the constructor.
// Note: All above comments apply to POD structures.
C c; // members are random
C* c = new C; // members are random (more officially undefined).

I believe valgrind is complaining because that is how C++ used to work. (I am not exactly sure when C++ was upgraded with the zero initialization default construction). Your best bet is to add a constructor that initializes the object (structs are allowed constructors).

As a side note:

A lot of beginners try to value init:

C c(); // Unfortunately this is not a variable declaration.
C c{}; // This syntax was added to overcome this confusion.

// The correct way to do this is:
C c = C();

A quick search for the "Most Vexing Parse" will provide a better explanation than I can.

How is this possible to use in c++?

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.



Related Topics



Leave a reply



Submit