I always thought that if I declare member of a class inside class this member is known at the entire scope of a class that is:
class X
{
public:
X(int a) :v_(a)
{}
private:
int v_;//even though v_ is declared here I'm using it in ctor which is above this line
};
So that makes sense to me.
Anyhow this doesn't because I'm getting error that v_ isn't known
class X
{
public:
X(decltype(v_) a) :v_(a)//error on this line, compiler doesn't know v_
{}
private:
int v_;
};
Would be glad to learn why.
I'm using intel compiler v14 SP1
Thank you.
3.3.7 Class scope
1 The following rules describe the scope of names declared in classes.
1) The potential scope of a name declared in a class consists not only of the declarative region following
the name’s point of declaration, but also of all function bodies, brace-or-equal-initializers of non-static
data members, and default arguments in that class (including such things in nested classes).
...
That means that you can use v_ in function bodies, constructor initializer lists and default arguments. You are not allowed to use v_ in parameter declarations the way you used it in your code.
For example, this shall compile
class X
{
public:
X(int a = decltype(v_)()) : v_(a)
{}
private:
int v_;
};
but not the second example in your original post.
Your code compiles with Clang.
Reading C++11 specifications you are not allowed to declare the variable after it is being used as function/constructor parameter.
In many cases classes including function signatures will be defined in headers, but function bodies in cpp files. Since the header will have been read by the compiler at the start of reading the cpp file, this problem does usually not occur. But indeed, C++ compilers don't look ahead.
Related
Consider the following code:
struct test {
auto func() -> decltype(data) {} // ERROR
int data;
};
int main() {
test t;
t.func();
}
It gives the following error:
main.cpp:2:29: error: 'data' was not declared in this scope
auto func() -> decltype(data) {}
However, if I place data above func(), it gives out no error (live code):
struct test {
int data;
auto func() -> decltype(data) {}
};
...
And so my question is, why is decltype not considering members declared after it (when decltype is used in a method declaration, not in the definition)? I also want to know if there are any change in this behavior in future iterations of the language standard.
Please note that I'm asking this because I was expecting decltype to behave differently. My coding convention is to place class data members below the class functions. Surely this different behavior would affect how I organize my class members. I would be very grateful if you can provide any workaround that would preserve my coding convention.
The trailing return type is part of the member function declaration, which does not have access to data members or member functions declared after it, unlike the member function definition, which does. I am not aware of any change in this behaviour in C++14.
See 3.4.1-7 of the C++11 standard, Unqualified name look-up:
A name used in the definition of a class X outside of a member function body or nested class definition
shall be declared in one of the following ways:
before its use in class X or be a member of a base class of X (10.2), or...
(emphasis mine)
I wonder if there is a reason why we can't initialize members at their declaration.
class Foo
{
int Bar = 42; // this is invalid
};
As an equivalent of using constructor initialization lists.
class Foo
{
int Bar;
public:
Foo() : Bar(42) {}
}
My personal understanding is that the above example is much more expressive and intentional. Moreover this is a shorter syntax. And I don't see any possibility of confusion with other language elements.
Is there any official clarification about this?
The initialization of non-static members could not be done like this prior to C++11. If you compile with a C++11 compiler, it should happily accept the code you have given.
I imagine that the reason for not allowing it in the first place is because a data member declaration is not a definition. There is no object being introduced. If you have a data member such as int x;, no int object is created until you actually create an object of the type of the class. Therefore, an initializer on this member would be misleading. It is only during construction that a value can be assigned to the member, which is precisely what member initialization lists are for.
There were also some technical issues to iron out before non-static member initialization could be added. Consider the following examples:
struct S {
int i(x);
// ...
static int x;
};
struct T {
int i(x);
// ...
typedef int x;
};
When these structs are being parsed, at the time of parsing the member i, it is ambiguous whether it is a data member declaration (as in S) or a member function declaration (as in T).
With the added functionality, this is not a problem because you cannot initialize a member with this parantheses syntax. You must use a brace-or-equal-initializer such as:
int i = x;
int i{x};
These can only be data members and so we have no problem any more.
See the proposal N2628 for a more thorough look at the issues that had to be considered when proposing non-static member initializers.
The main reason is that initialization applies to an object, or
an instance, and in the declaration in the class there is no
object or instance; you don't have that until you start
constructing.
There's been some evolution in this regard. Already, at the
very end of standardization of C++98, the committee added the
possibility to do this for static const members of integral
type---mainly because these can be used in contexts where the
compiler must be able to see the initialization. In C++11, the
language has been extended to allow specifying an initializer in
the declaration, but this is just a shorthand—the actual
initialization still takes place at the top of the constructor.
When two or more objects(instance of the class) are declared, those objects share these data members. so value can be initialized with the help of constructor. so we can't initialize the class members during declaration.
I got 17 integer constants that I'd like to have as private in my class. Is it really necessary to use initialization list?
I read somewhere that I can assign values to constants in the header file, but it doesn't seem to work. I get this error message:
sorry, unimplemented: non-static data member initializers
Is it really necessary to use initialization list?
In modern (2011-era) C++, no. In older versions of the language, yes.
Your error message is apologising that your compiler doesn't support the new initialisation syntax for non-static members yet. Assuming you're using GCC (since I recognise that error from that compiler), then according to this page you'll need to upgrade to at least version 4.7 for that feature.
Alternatively, since they're private and constant, you might consider moving them out of the class into a local namespace in the class's implementation file. Of course, that will only work if you don't need to access them from any inline member functions.
Finally, if they have the same values for all instances of the class (which is likely, since they are const and you're able initialise them independently of the constructor arguments), you could declare them static. Then they can be initialised in their declaration (although older compilers might only allow that if they have an integer type). However, if they are odr-used (roughly speaking, if you need to take a pointer or reference to them), then they will also need to be defined in exactly one source file.
.h:
class MyClass {
public:
MyClass();
~MyClass();
int doSomething();
private:
const int m_newint = 1;
const int m_dosomething = 2;
};
.cc:
MyClass::MyClass() {}
MyClass::~MyClass() {}
int MyClass::doSomething() {
return m_dosomething;
}
Is valid C++11 code, make sure your compiler is set to -std=c++11 to use the
feature.
So I was learning about classes and I stumbled upon something I found was quite awkward to me.
class Nebla
{
public:
int test()
{
printout();
return x;
}
void printout()
{
printout2();
}
private:
int x,y;
void printout2()
{
cout<<"Testing my class";
}
};
I found that in a class I can use functions before I declare them (prototype them)
You can see I used printout() , printout2() before decleration.
And I can use variables also before declaring them
You can see I did return x; before declareing x.
Why can I use functions and variables in classes before declaration but outside the class if I do that, I get an error?
Thanks
Good question; I've relied on that feature for years without thinking about it. I looked through several C++ books to find an answer, including Stroustrup's The C++ Programming Language and The Annotated C++ Reference Manual, but none acknowledge or explain the difference. But, I think I can reason through it.
The reason, I believe, that your example works is that the bodies of your test and printout aren't truly where they appear in your file. The code
class MyClass {
void someFun() {
x = 5;
}
int x;
};
...which appears to violate the rule of having to declare variables before you use them, is actually equivalent to:
class MyClass {
void someFun();
int x;
};
void MyClass::someFun() {
x = 5;
}
Once we rewrite it like that, it becomes apparent that the stuff inside your MyClass definition is actually a list of declarations. And those can be in any order. You're not relying on x until after it's been declared. I know this to be true because if you were to rewrite the example like so,
void MyClass::someFun() {
x = 5;
}
class MyClass {
void someFun();
int x;
};
...it would no longer compile! So the class definition comes first (with its complete list of members), and then your methods can use any member without regard for the order in which they're declared in the class.
The last piece of the puzzle is that C++ prohibits declaring any class member outside of the class definition, so once the compiler processes your class definition, it knows the full list of class members. This is stated on p.170 of Stroustrup's The Annotated C++ Reference Manual: "The member list defines the full set of members of the class. No member can be added elsewhere."
Thanks for making me investigate this; I learned something new today. :)
Just to make it clear, this is required by the C++ Standard, not just the way several compilers handle class definitions.
N3242 3.3.7:
The potential scope of a name declared in a class consists not only of the declarative region following the name's point of declaration, but also of all function bodies, brace-or-equal-initializers of non-static data members, and default arguments in that class (including such things in nested classes).
The reason you are able to do this is because by the time you call test, printout or printout2, they will have already been created. If you call the function outside the arbitrary function before it's implementation, then you'll get an error.
Think of class member-functions as being asynchronous with the flow of evaluation of the rest of the class. This won't work with stand alone functions, but you can access data members that haven't been instantiated yet. I'm not completely sure why we are able to do this, but I think it has to do with instantitation of the class object.
Besides Philip's good response, Stroustrup gives a nice explanation of Name Lookup Rules in The Design and Evolution of C++. This is described in "6.3 Clarifications". In 6.3.1.1, "The ARM Name Lookup Rules", he mentions 2 rules defined in the ARM:
[1]The type redefinition rule:A type name may not be redefined in a class after it has been used there.
[2] The rewrite rule: Member functions defined inline are analyzed as if they were defined immediately after the end of their class declarations.
So in your case it would apply the rewrite rule (as Philip deduced), that's why you can forward reference those class members.
This book may be mainly of historical interest (it's written in '94), but I think those rules are applied the same way today.
Why can I use functions and variables in classes before declaration
This is because the body of a member function is a complete-class context of a class, as mentioned in the quoted statements below:
From class.mem.general#6:
6. A complete-class context of a class is a:
function body ([dcl.fct.def.general]),
default argument,
noexcept-specifier ([except.spec]), or
default member initializer
within the member-specification of the class.
This means that the usage of printout inside member function test and the usage of printout2 inside member function printout is allowed here even though those members appear later when writing the class definition.
class C : public B
{
public:
void C::Test();
};
What is the point of specifying C in the declaration of the member function?
You shouldn't do this. Many modern compilers will treat this as a syntax error, for example, g++ 4.2.1 will!
This is only neccessary when defining the method outside of the class:
class C : public B
{
public:
void Test();
};
void C::Test() { ... }
Not only there's no point, it is downright illegal (see 8.3/1 in the language standard). In general in C++ language qualified names are allowed only when you are referring to a previously declared entity, but not when you are introducing a new entity (there are some exceptions from this rule, but none of them apply here).
The code you posted would require a diagnostic message from any conforming compiler, since your member function declaration is invalid.
There is no point, no need to do this. Since the declaration of Test is inside the scope of the declaration of C, the compiler knows that the function Test is a member of C.