nested class as a parameter for the member function in C++ - c++

I am integrating someone's code, which has everything in one cpp file. The main code is like this:
class Outer
{
public:
struct Inner
{
struct In_inner
{
...
}
}
int func(Inner& inn, Inner::In_inner& in_inn)
{
...
}
}
To make separation, should I add the "Outer::" for the "Inner" parameter, as follows?
in the header file
class Outer
{
public:
struct Inner
{
struct In_inner
{
...
}
}
int func(Inner& inn, Inner::In_inner& in_inn);
}
and in the cpp file:
int Outer::func(Outer::Inner& inn, Outer::Inner::In_inner& in_inn)
{
...
}
It sounds a bit weird to me that the parameter list is a bit different from the declaration. Also, can I keep everything in the same file again, and include it as a header file?
Thanks for any comments!

int Outer::func(Outer::Inner& inn, Outer::Inner::In_inner& in_inn)
Yes. You've correctly written this. You've to add Outer:: if you define it outside the class.
It sounds a bit weird to me that the parameter list is a bit different from the declaration
That is okay. The function is defined outside the class. You're no more in the scope of the class. Hence it looks a bit different.
But if you don't want it to look different, then you can write Outer:: in the declaration as well, as shown below:
class Outer
{
public:
//...
int func(Outer::Inner& inn, Outer::Inner::In_inner& in_inn);
};
This is fine, and would work because Outer is an injected-name, its available inside the class as well.
struct A
{
struct B {
struct C {};
};
B b1; //okay - as usual
A::B b2; //this is also okay - not so usual though
B::C c1; //okay - as usual
A::B::C c2; //this is also okay - not so usual though
A::A::A::A::A::A *pA; //this is very very unsual. But it is also okay!
};
The last line is okay, because the name A is injected inside the definition of class A. Hence it becomes recursively available.
See it compiles fine:
http://www.ideone.com/oiy2h

The parameter list isn't different; the types are the same. It's not uncommon to have explicitly qualified std:: members in the header file and use using namespace std; in the source file, either. That's basically the same thing.
It doesn't matter how you qualify the types, as long as they refer to the same types. And because you are not in the scope of Outer in the source file, the explicit qualification is necessary there.

Within the class declaration/definition, you are in the scope Outer::. Outside that (in your .cpp), you are not.
Yes, you can keep the function definition in the header: it is an implicit inline.

Related

C++ method implementations: Can I avoid typing the class name each time?

When I have a C++ class MyClass in namespace mynamespace, I implement its methods as
void mynamespace::MyClass::method() { … }
I can wrap that in a namespace to shorten individual definitions to
namespace mynamespace {
void MyClass::method() { ... }
}
Is there a way to avoid having to retype MyClass:: as well so I can copy everything before the { to the header as a prototype more easily whenever the signature changes, without having to remove the MyClass:: every time?
I thought "a class is also a namespace, maybe I can do"
namespace mynamespace::MyClass {
void method() { ... }
}
but that complains that I was re-defining MyClass as a different thing. using mynamespace::MyClass; also didn't work (but would be bad anyway because how would I declare a standalone function anywhere below that line in that file if it worked).
Is there a solution to this, or is it simply not possible in C++?
No, the qualified class name must appear on any class member defined outside the class definition. (And there can only be one class definition, which is normally in a header file.)
The C++ Standard spells out this rule in [class.mfct]/4:
If the definition of a member function is lexically outside its class definition, the member function name shall be qualified by its class name using the ​::​ operator.
and similarly in [class.static.data]/2 for static data members.
You might abbreviate this qualification using preprocessor macros, but that would seriously harm legibility and is not a common practice.
There is no idiomatic way to avoid this. Even if you or someone else might come up with a "hack" (macro-based, for example), it would make the code less readable for everyone. The normal and expected way to write C++ is for the member functions to have the preceding MyClass:: when defined outside the class definition.
I would suggest to look for a tool that can update signatures between header and source file on command.
Or, as the comments suggest, provide the definitions of your functions right with the declaration inside the class definition (i.e. provide inline definitions). But that has its own disadvantages.
Using C++20 modules, you can implement a class in one file:
module myproject.mymodule;
namespace mynamespace {
export struct my_class {
auto my_method() -> int {
return 8;
}
};
}
Or export a whole namespace fragment:
export namespace mynamespace {
struct my_class {
auto my_method() -> int {
return 8;
}
};
auto also_exported() -> void {
// ...
}
}
Then, instead of including it, you can import that module:
import myproject.mymodule;
auto frob() -> void {
auto my_instance = mynamespace::my_class{};
}

Can a class name instead of a namespace be pre-pended to :: for scope resolution?

So as I understand it, when I see double colons(abc::xyz) used the thing on the left is a namespace and the thing on the right can be a function or variable of some sort that is defined in that namespace. ex. namespace::bar, namespace::foo()
Now, can the thing on the left be a class? ex. class::bar, class::foo()
If so, does anyone have any info on this. I can find lots of info of scope resolution pertaining to namespaces but not when it comes to classes.
In my situation I am going through a rather large project of code that is from another individual.
The code usage that I am trying to understand is that I have the following line of code...
multi_img::ptr input = imginput::ImgInput(config.input).execute();
On the right the imginput::ImgInput() can be found because there is a namespace imginput that I can find. But on the left, the multi_img::ptr, there is no multi_img namespace in the project. There is a multi_img class that contains the following line...
typedef boost::shared_ptr<multi_img> ptr;
I believe this is what multi_img::ptr means but can not find any documentation to back up my assumption.
Now, can the thing on the left be a class?
Yes it can, and to justify consider the following example:
#include <iostream>
class foo {
public:
void fun() const { std::cout << "foo:fun()" << std::endl; }
};
int main() {
foo f;
f.foo::fun();
return 0;
}
DEMO
Every class member lies in the scope of its class.
Edit after #Cheersandhth.-Alf constructive comment:
Thus, you can access a member through an object with either the classical way (e.g., f.fun()) in which case you'll have a virtual call or you call it like in the example (i.e., f.foo::fun()) in which case you explicitly disambiguate the scope of member function at compile time.
Yes, you can have a class name on the left of ::. It is used to denote a member of that class. The multi_img class has a member called ptr. As you have shown, that member is a typedef. That is, the type multi_img::ptr is a synonym of boost::shared_ptr<multi_img>.
Note that :: is used to access static members and nested types, since these only require the name of the class and not a particular object that of that class type. We use . and -> to access non-static data members of a particular object.
Usually the classname::member notation is used to
Access static members.
E.g. Blah::uuid.
Prevent virtual call.
E.g. in Blah::foo, a call like Base::foo().
Disambiguate.
E.g. with two bases A and B, both of which provides a foo, a call like B::foo().
Some older libraries use classes instead of namespaces. I vaguely recall an XML library and a GUI library. Not sure which.
Personally I do the class-as-faux-namespace for enumeration types, e.g.
struct Weekdays
: Non_instantiable
{
enum Enum { wednesday, friday, saturday };
};
used like
auto foo() -> Weekdays::Enum { return Weekdays::friday; }
even after C++11 started supported enum class.
Sometimed it is difficult to know whether the nested name specifier denotes a namespace or a class because the syntax is the same. Moreother the same name can denote either a namespace or a class depending on the declaration region where the name is used. For example
namespace A
{
struct A
{
static int a;
static int b;
static int c;
};
int A::a = 5;
}
int A::A::b = 10;
int A::A::c = a;
The most appropriate documentation is the C++ Standard. You may download a working draft of the Standard from the ISO-IEC site
As for the typedef that defines a type
typedef boost::shared_ptr<multi_img> ptr;
then it seems that it is defined in the class definition of multi_img. So if the name is used outside the class scope it shall be qualified
multi_img::ptr input = imginput::ImgInput(config.input).execute();

Unknown return type error (C++)

My problem is that i need to first define my interface and then implement it further in code but my problem i that function that should return type that is known inside class seems to be unknown outside class when i implement method.
This is my code:
class Test {
class Inner {
};
public:
Inner* foo (void);
};
Inner* Test::foo(){
}
This code produce error because type Inner is unknown for the function outside the class. Can anyone help me how to make simple function that would return type defined only inside class ?
Thank you for any help.
You need
Test::Inner* Test::foo(){
}
If a member function definition is outside the class definition, then the return type is not in the class scope, unlike the rest of the function, so you need to explicitly qualify the return type.
Since no one has mentioned it, you can also do this in C++11:
auto Test::foo() -> Inner * {...}
This can be useful if the fully qualified name is long. In C++14, you can leave off the trailing type part and just do:
auto Test::foo() {...}
This will deduce the return type.
Inner is a nested class and outside class Test it has to be fully qualified:
Test::Inner* Test::foo() {
//...
}
because in global scopeInner is indeed unknown, only Test::Inner, so a Inner inside Test is known. You could also have another Inner in global scope, just the same as with Test, and this will be other Inner, not Test::Inner.
You does not seem to specify the scope so it, of course, remains unknown. The C++ compiler will look for an Inner class outside your Test class which could also present as a different class, but it is not in your particular case.
That is why you will need to also provide the scope, even for the return type. That is not to say you would need to use the scope inside your test class, but outside, you will have to due to that.
Thereby, the correct code would be something like this:
class Test {
class Inner {
};
public:
Inner* foo (void);
};
Test::Inner* Test::foo(){
//^^^^
}
Strictly speaking, if you have a recent compiler, you could even use auto, but then it gets a bit less comprehensive.
class Test {
class Inner {
};
public:
Inner* foo (void);
};
Test::Inner* Test::foo(){
}

Why I can't separately write namespace's hierarchy in the header file?

I write some header file. I want separately declare the namespaces hierarchy (for clarity), and and then declare functions and classes. For me it looks as a table of contents in the document. It would be very convenient for me: to see the full hierarchy of namespaces in one place. I write this:
// Namespaces hierarchy:
namespace Bushman{
namespace CAD_Calligraphy{}
//...
}
// Declarations of classes and functions
class Bushman::CAD_Calligraphy::Shp_ostream{
public:
explicit Shp_ostream(std::ostream& ost);
};
But MS Visual Studio shouts on such way of creation of the header file. I should write so:
namespace Bushman{
namespace CAD_Calligraphy{
class Shp_istream{
public:
explicit Shp_istream(std::istream& ist);
};
}
}
Why the first variant doesn't work? Is this restriction of the C++, or IDE?
P.S. My additional question is here.
Thank you.
The restriction is in §9/1: "If a class-head-name contains
a nested-name-specifier, the class-specifier shall refer to
a class that was previously declared directly in the class or
namespace to which the nested-name-specifier refers[...]". In
other words, the first appearance of the class name cannot be in
something like Bushman::CAD_Calligraphy::Shp_ostream.
What you can do is add forward declarations in your initial
declaration of the hierarchy:
// Namespaces hierarchy:
namespace Bushman{
namespace CAD_Calligraphy{
class Shp_ostream;
//...
}
//...
}
// Declarations of classes and functions
class Bushman::CAD_Calligraphy::Shp_ostream{
public:
explicit Shp_ostream(std::ostream& ost);
};
Depending on how your headers are organized, this might even be
better from the human point of view: your header starts with
a sort of index of what is defined in it.
To quote the standard: Section 7.3.1.2 point 2:
Members of a named namespace can also be defined outside that
namespace by explicit qualification (3.4.3.2) of the name being
defined, provided that the entity being defined was already declared
in the namespace and the definition appears after the point of
declaration in a namespace that encloses the declaration’s namespace.
namespace Q {
namespace V
void f();
}
void V::f() { /∗ ... ∗/ } // ok.
void V::g() { /∗ ... ∗/ } // Error: g() is not yet a member of V
namespace V
void g();
}
}
namespace R {
void Q::V::g() { /∗ ... ∗/ } // // error: R doesn’t enclose Q
}
So, you could do what you have in your original post, if you declare the class name there:
namespace Bushman{
namespace CAD_Calligraphy {
class Shp_ostream;
...
}
}
That's how C++ works.
It's consistent with other nested declarations: you can't add members to a class from outside the class:
class A
{
};
void A::f() { } // Error!
And you can't add enumerators to an enum from outside:
enum E { E1 = 1, E2 = 2 };
E::E3 = 3; // Error!
You need to "open" the scope and declare the entity inside the scope. Once it's declared you can define it outside that scope, using a nested-name:
class A
{
void f(); // declare
};
void A::f() { } // define
First of all, C++ is not designed to work like that. So it is not a surprise that this is happening.
But, since you're using Visual Studio, you could take advantage of partial classes. Unfortunately, it seems this characteristic is only related to C++/CX so maybe yo won't be able to use it.
You will still need to declare a partial class in your namespace hierarchy, but I guess it could be empty.
To be honest, I haven't used this feature and I don't know how far can it be bent in order to achieve what you want. But you could anyway give it a try.
Remember that this is a Visual Studio extension, so your code won't be cross-platform.
Hope this helps. Somehow.

Where to place Structs and Enums in C++ class + final constants

I have started reading C++ and I have a question about classes and member variables of type Enum and Struct. Where should I declare Enums/Structs so that I can use them as member variables when I separate header and implementation file? And also, how can I make a final member variable in a C++ class? I am just getting compilation error when adding const int myTest as a member variable, where should I initialize them?
The header file is like a person saying 'I can do this, that and the other' - so put declarations into it - enums, structs, class declarations, constants, ...
The implementation file is like a person saying 'I can do this and this is how I can do it' - it produces a recipe - Actual machine code for the CPU to crunch.
const says - do not change me. To intialise in a class you need:
class X
{
private:
const int y;
public:
X() : y(5) {}
};
for example. If you are learning about C++ const is a very useful tool to prevent you making a multitude of errors.
the simplest solution is to simple declare the enums & structs directly before the class they are a member of:
struct Gizmo
{
int n_;
};
class Foo
{
public:
Gizmo gizmo_;
};
If Gizmo is logically coupled to Foo (eg, if you would never use a Gizmo outside the context of using a Foo), it might also make sense to make Gizmo a nested class:
class Foo
{
public:
struct Gizmo
{
int n_;
};
Gizmo gizmo_;
};
If you want to instantiate a Gizmo declared this way, you can resolve the scope yourself:
Foo::Gizmo gizmo;
Finally, if Gizmo and Foo are not logically coupled, and you might use Gizmos all over the place without needing a Foo, then it probably belongs in its own header file.
gizmo.h
struct Gizmo
{
int n_;
};
foo.h
#include "gizmo.h"
class Foo
{
public:
Gizmo gizmo_;
};
Where should I declare Enums/Structs so that I can use them as member variables when I separate header and implementation file?
You must declare them before their use, that is. before the declaration of the member in the class of their type. Either:
you define them in their own header file and #include that file in your class' header file (before the declaration of your class)
or you define them just before your class
or you define them in your class before the members
I am just getting compilation error when adding const int myTest as a member variable, where should I initialize them?
In the constructor, using initializers. Ie.:
Clazz::Clazz() : my_const_var(0) { ... }
If you're going to add an enum or struct as a member variable of the class, the definition of the enum or struct must be complete before you declare the member. This can either be inside the class, outside of the class but coming before it in the .h header, or in a different .h header that is included before or within the current one.
There shouldn't be any problem declaring a member variable as const, but it places a restriction on how it must be initialized. You must do it in the initializer list of the constructor.
MyClass::MyClass() : myTest(value)
{
}