What Is the Class Keyword Before a Function Argument

What is the class keyword before a function argument?

If a function or a variable exists in scope with the name identical to the name of a class type, class can be prepended to the name for disambiguation, resulting in an elaborated type specifier.

You are always allowed to use an elaborated type specifier. Its major use case, however, is when you have a function or variable with an identical name.

Example from cppreference.com:

class T {
public:
class U;
private:
int U;
};

int main()
{
int T;
T t; // error: the local variable T is found
class T t; // OK: finds ::T, the local variable T is ignored
T::U* u; // error: lookup of T::U finds the private data member
class T::U* u; // OK: the data member is ignored
}

class' keyword in function signature - is it standard C++?

The class keyword is allowed here, it's just rare to see it placed here since it can either be completely omitted (if this class has been previously declared) or replaced with the forward declaration:

void foo(const class FPostConstructInitializeProperties& p){ ... }

which is equivalent to:

class FPostConstructInitializeProperties; // <-- forward declaration
void foo(const FPostConstructInitializeProperties& p){ ... }

Don't get confused with the weird naming conventions. The snippet you have provided expresses something like this:

class B{
public:
B(){ }
B(const B& b){ };
};

class A{
public:
B my_b;
A(const class B& b) : my_b(b) { } // <-- class keyword in ctor's param decl.
};

that could be used for example like this (but I guess it's clear enough already):

int main() {
B b;
A a(b);
}

class' keyword in variable definition in C++

An elaborated type specifier is a type name preceded by either the class, struct, enum, or union keyword.

class identifier 
struct identifier
enum identifier
union identifier

An elaborated type specifier is used either for emphasis, or to reveal a type name that is hidden by the declaration of a variable with the same name in the same scope.

source

Declaring a variable with class keyword vs Declaring one without class keyword in function signatures

Using keyword class, struct, enum in a type parameter declaration is called elaborated type specifier. It introduces the new type in the scope where the function is declared.
It is similar to forward declaration.

There is also another using of such a declaration. For example if a name of an object or a function name hides a class or enum with the same name. For example

struct A {};

A A; // now A is seen as an identifier of the object

void f( struct A );

c++ class object as function argument

They are legal and normally not required.

They are only required when there is ambiguity as to what A is.

For example:

#include <string>

extern void A();

class A
{
private:
std::string name;
public:
A(std::string n) :name(n){}
friend bool operator < (const class A& a1, const class A &a2);
};

// removing `class` here would result in a compiler error as it would be
// ambiguous as to whether you meant the function A or the class A
bool operator < (const class A& a1, const class A &a2)
{
return a1.name < a2.name;
};

What does class mean before parameter?

How Unreal works

As you might know, Unreal manages multiple implementations of the same base classes to define a common ground. Every developer must, then, create child classes from the ones the engine has to offer in order to perform tasks within the Engine.

In this case, it's about an InputComponent, which is used to handle User Input, interpret it and pass it along to Controllers and/or, subsequently, Pawns.

For example, if you want to define elements such as Pawns, PlayerControllers, AIControllers, the HUD and the like, you do so in a GameMode you then configure into the Project Settings or, directly, into the level through the World Settings (in case your level needs a specific GameMode). Those references are classes as well, which will be instantiated by the Engine in due time to setup the Game.

Here comes the pitfall

With this in mind, here comes the downside. In UE4 C++ (yeah, it's a thing!), since the engine ties the loose ends, sometimes you won't be able to use certain classes because they're not declared. Of course, you can include them but think about it: how many circular dependencies will be created if you make all the inclusions you need for one class only to find another one might indirectly require that one?

The solution is Forward Declaration. This case, however, is a special flavor called Shorthand Forward Declaration in which you declare a type in the exact place where you use the class.

This is extremely handy if you're just using it once, so you don't end up with a terrible list of declarations at the start of your file.

Bringing this to the real world

For example, should you want to know the current default Pawn class defined, you can check the GetDefaultPawnClass public variable in your GameMode (Let's call it MyGameMode). The variable is defined as follows:

TSubclassOf < APawn > DefaultPawnClass

See that TSubclassOf? That's actually a Class Template to ensure type safety. It's actually a hint to the Editor to show you only classes derived from APawn.

Should you use a custom type and based in what I've been discussing so far, you could find stuff like this:

TSubclassOf<class ASpeedyPawn> MySpeedyPawn;

What is different about C++ class function parameter syntax when one of them is a struct?

C++ is compiled from the top down to the bottom of the source code. Except in templates, each time an identifier is encountered, name lookup is performed. This means the compiler tries to find a reachable declaration of the identifier in the previous part of the source code.

Here you use the identifier freq_pair the first time in the function parameter inside

int freq_sort(unsigned char* source, struct freq_pair* target);

Because it was not declared beforehand, the compiler does not know yet what freq_pair is supposed to be. Usually that would result in an error saying that freq_pair is undeclared. However the struct keyword basically tells the compiler: "freq_pair is a class type and if you don't find such a class type, then declare it here."

Therefore freq_pair will be declared, but the question is where exactly (i.e. in which scope) it will be declared. It could be declared as a nested class (struct and class both introduce classes, in C++ there is no distinction between the two with regards to type identity) inside TargaImage, as a local class to the function or as a global class. In fact the latter is the case, as [basic.scope.pdecl]/7.2 of the C++17 standard (draft N4659) specifies (see also this question for a similar case):

for an elaborated-type-specifier of the form

class-key identifier


if [...]; otherwise, except as a friend declaration, the identifier is declared in the smallest namespace or block scope that contains the declaration.

An elaborated-type-specifier is a type specifier that uses struct or one of the other class-key keywords, i.e. exactly what you have with struct freq_pair. Your function declaration is inside a class scope (which is neither a namespace scope nor a block scope), therefore the declaration of freq_pair cannot be placed there. The next smallest scope containing class TargaImage {...}; is the global scope, which is considered a namespace scope. Thus the line

int freq_sort(unsigned char* source, struct freq_pair* target);

declares a global struct freq_pair and the type referred to in the declaration is that type.

Then

struct freq_pair {
unsigned char val;
int count;
};

defines a class freq_pair nested inside the class TargaImage. This is not the same class as the global one your declared beforehand.

Then we come to the definition

int TargaImage::freq_sort(unsigned char* source, struct freq_pair* target){
return 0;
}

Here, because we are defining a function which is part of TargaImage, the name freq_pair is first looked up inside TargaImage, where we now see the definition struct freq_pair {...}; which declared a freq_pair nested inside TargaImage, i.e. TargaImage::freq_pair. The struct keyword does not have any further effect if a type matching the name can be found, so freq_pair in this definition now refers to TargaImage::freq_pair.

As a result you have declared a member function taking a pointer to the global ::freq_pair, but tried to define a member function taking a pointer to the nested ::TargaImage::freq_pair. The compiler complains that these do not match up.


To resolve the issue remove all the struct keywords inside variable declarations and use it only to define or explicitly forward-declare classes. As you can see, using it as elaborated type specifier only causes headaches. The same rule applies to the other elaborated type specifiers, i.e. those beginning with class/enum/union.

Doing so will however result in an error because freq_pair is not found in the member declaration as I explained above. This is easily resolved by moving the definition of freq_pair before the point of use:

class TargaImage
{
public:
//data member
struct freq_pair {
unsigned char val;
int count;
};

//function
int freq_sort(unsigned char* source, freq_pair* target);
};

int TargaImage::freq_sort(unsigned char* source, freq_pair* target){
return 0;
}

If that is not possible for whatever reason, then you can use a forward declaration to make sure that the first lookup finds the correct type (even if it is incomplete at that point):

class TargaImage
{
public:

//explicit forward declaration
struct freq_pair;

//function
int freq_sort(unsigned char* source, freq_pair* target);

//data member
struct freq_pair {
unsigned char val;
int count;
};
};

int TargaImage::freq_sort(unsigned char* source, freq_pair* target){
return 0;
}

Also note that freq_pair is a nested class, not a data member.

What does the 'new' keyword before the parameter list mean in a typscript arrow function?

It's a constructor type. It means that when you invoke it with new, you can give it a props argument and an optional context argument, and it'll construct an instance of type T.

Here's an example:

class Foo {
private value: number;
constructor(x: number, y: number = 1) {
this.value = x + y;
}
}

const foo: new (arg1: number, arg2?: number) => Foo = Foo;
// can be invoked like this (with new)
const x1: Foo = new foo(1);
const x2: Foo = new foo(1, 2);
// cannot be invoked without new
// these lines will error at both compile- and run-time
const y1: Foo = foo(1);
const y2: Foo = foo(1, 2);

Why using the const keyword before and after method or function name?

const T& get_data() const { return data_; }
^^^^^

means it will return a const reference to T (here data_)

Class c;
T& t = c.get_data() // Not allowed.
const T& tc = c.get_data() // OK.




const T& get_data() const { return data_; }
^^^^^

means the method will not modify any member variables of the class (unless the member is mutable).

void Class::get_data() const {
this->data_ = ...; // is not allowed here since get_data() is const (unless 'data_' is mutable)
this->anything = ... // Not allowed unless the thing is 'mutable'
}


Related Topics



Leave a reply



Submit