Here's my code/namespace:
namespace myNamespace {
enum MyType {
ASD1,
ASD2,
ASD3
};
struct MyClass {
MyType mMyType;
MyClass(MyType myType = MyType::ASD1) : mMyType(myType) {
}
};
}
Now if I try, within another struct, this code:
struct X
{
myNamespace::MyClass *pMyClass1 = new myNamespace::MyClass(myNamespace::MyType::ASD2);
};
it works perfectly, but if I try this:
struct X
{
myNamespace::MyClass mMyClass1(myNamespace::MyType::ASD2);
};
it says 'myNamespace::MyType::ASD2' is not a type.
Since its all declared before, why this?
Inside class, you might use {..} or = .. syntax, not (..):
struct Test {
myNamespace::MyClass mMyClass1{myNamespace::MyType::ASD2};
// myNamespace::MyClass mMyClass1 = myNamespace::MyClass{myNamespace::MyType::ASD2};
};
You have to use the brace-or-equal-initializer. You may not use an initializer in parentheses without the sign =.
From the C++ Standard (12.2 Class members)
member-declarator:
declarator virt-specifier-seqopt pure-specifieropt
declarator brace-or-equal-initializeropt
identifieropt attribute-specifier-seqopt : constant-expression
For example
myNamespace::MyClass mMyClass1 { myNamespace::MyType::ASD2 };
or
myNamespace::MyClass mMyClass1 = myNamespace::MyType::ASD2;
The last initialization is valid because the constructor is a conversion constructor
Related
I tried to create a class with an enum, and a function that returns a variable of this enum. But I ran into a problem:
This works:
class SizeBoxClass {
public:
enum BoxType{xBox, yBox};
BoxType intersects() {
return xBox;
}
}SizeBox;
But this does not:
class SizeBoxClass {
public:
BoxType intersects() {
return xBox;
}
enum BoxType { xBox, yBox };
}SizeBox;
I get "BoxType is undefined" at the line of the function declaration...
Why? I thought declaring a class member after its use was not a problem.
enum BoxType { xBox, yBox }; is a type declaration (and also definition), not a member variable or member function.
Types need to be declared before first use.
In MyClass below, enum MyType is defined inside the class.
In main, I create a variable of MyClass::MyType t. This compiles fine. However, when I wish to assign it a value such as OPEN, there is a compilation error "OPEN was not declared in this scope"
Firstly it probably doesn't make sense declaring an enum type inside the class and limiting its scope there and then creating a variable of that enum type elsewhere, but I'm just trying to understand what's happening.
In the first place, how am I able to create a variable of MyType in main when an object hasn't even been created? Are enums and struct types defined in a class like that implicitly static?
Also, the compiler has access to the enum code, so why doesn't it understand "OPEN"? Thanks
#include <iostream>
using namespace std;
class MyClass
{
public:
enum MyType
{
OPEN,
CLOSED
};
struct MyStruct
{
int val1;
int val2;
};
};
int main()
{
MyClass::MyType t;
t = OPEN; // compilation error
return 0;
}
Your enum MyType is inside the class, so its values are expected to be accessed through the class and the enumeration. You are already creating a MyType without instantiating the class, but an example of instantiation through the class is also provided.
class MyClass
{
public:
enum MyType
{
OPEN,
CLOSED
};
struct MyStruct
{
int val1;
int val2;
};
};
int main()
{
MyClass::MyType t; // Already a MyType value!
MyClass c; // Building your class
t = MyClass::MyType::OPEN; // No compilation error
t = c.OPEN; // Accessing enum through instantiated class
return 0;
}
Like Remy said. Value OPEN is a part of MyClass class and is only reachable in that classes scope. For your compiler to see it and use it you need to acces it through MyClass::OPEN.
(In addition to what others wrote)
If supported by the compiler (Since C++ 11),
it is a better practice to use enum class:
enum class MyType
{
OPEN,
CLOSED
};
"The enum classes (“new enums”, “strong enums”) address three problems with traditional C++ enumerations:
1) Conventional enums implicitly convert to an integer, causing errors when someone does not want an enumeration to act as an integer.
2) Conventional enums export their enumerators to the surrounding scope, causing name clashes.
3) The underlying type of an enum cannot be specified, causing confusion, compatibility problems, and makes forward declaration impossible."
ISOCPP FAQ - enum class
-
In that case, use the syntax:
int main()
{
MyClass c;
MyClass::MyType t;
t = MyClass::MyType::OPEN;
return 0;
}
See [decl.enum]/11:
Each enum-name and each unscoped enumerator is declared in the scope
that immediately contains the enum-specifier. Each scoped enumerator
is declared in the scope of the enumeration. These names obey the
scope rules defined for all names in [basic.scope] and [basic.lookup].
[ Example:
enum direction { left='l', right='r' };
void g() {
direction d; // OK
d = left; // OK
d = direction::right; // OK
}
enum class altitude { high='h', low='l' };
void h() {
altitude a; // OK
a = high; // error: high not in scope
a = altitude::low; // OK
}
— end example ] An enumerator declared in class scope can be referred
to using the class member access operators (::, . (dot) and ->
(arrow)), see [expr.ref]. [ Example:
struct X {
enum direction { left='l', right='r' };
int f(int i) { return i==left ? 0 : i==right ? 1 : 2; }
};
void g(X* p) {
direction d; // error: direction not in scope
int i;
i = p->f(left); // error: left not in scope
i = p->f(X::right); // OK
i = p->f(p->left); // OK
// ...
}
— end example ]
I'd like to have a class that has static members to itself, but I can't figure how to do that. Is that even possible?
I get the error:
only static const integral data members can be initialized within a class
Code:
namespace misc
{
class CData
{
public:
CData( ) { };
CData( int d );
CData& operator = ( const CData& d );
static const CData FIRST = CData( 512 ); //how?
private:
int data;
};
}
As I use FIRST a lot I would like to statically access it using misc::CData::FIRST without the need to declare it somewhere in the scope. Is that by any chance possible?
... without the need to declare it somewhere in the scope. Is that by any chance possible?
No, it's not possible without declaring it (which you already tried to do in your class declaration). You probably meant, without defining it outside your class declaration. Again the answer is no.
You have to separate declaration and definition for this case (it only works with primitive integral types like int to initialize these directly in the class declaration).
First have a simple declaration in your class declaration (usually something like CData.hpp)
namespace misc {
class CData {
public:
CData( ) { };
CData( int d );
CData& operator = ( const CData& d );
static const CData& FIRST;
private:
int data;
};
}
and then define it in a separate compilation unit (usually something like CData.cpp)
namespace misc {
const CData& CData::FIRST = CData( 512 );
}
For non-integral data, something like this is preferred since it avoids the static initialization fiasco.
static const CData FIRST()
{
static CData first(512); //only initialized once, when first requested
return first;
}
... without the need to declare it somewhere in the scope. Is that by
any chance possible?
No.
C++ Standard n3337 § 9.4.2/2
Static data members
The declaration of a static data member in its class definition is not
a definition and may be of an incomplete type other than cv-qualified
void. The definition for a static data member shall appear in a
namespace scope enclosing the member’s class definition. (...)
You can declare a static data member in class:
namespace misc {
class CData {
public:
//...
static const CData FIRST; // declaration
//...
}
and define it in (exactly) one of the .cpp files:
namespace misc {
CData CData::FIRST = CData( 512 ); // definition
}
This is preferred solution, however you need to have this definition out of your class. You could have defined the member in class if it was of an integral type
C++ Standard n3337 § 9.4.2/3 says
If a non-volatile const static data member is of integral or
enumeration type, its declaration in the class definition can specify
a brace-or-equal-initializer in which every initializer-clause that is
an assignment- expression is a constant expression (...)
I have created one scenario where I want help. Below code is the sample test application for same.
#include <iostream>
using namespace std;
class A
{
public:
typedef int mytype;
mytype GetInt() { return 1;}
};
class B
{
public:
typedef char mytype;
};
class C : public A, public B
{
};
class D : public C
{
public:
void scenario()
{
mytype m = GetInt();
}
};
int main()
{
D d1;
d1.scenario();
return 0;
}
Compiling code using : g++ tmp.cpp
Error:
tmp.cpp:27:9: error: reference to ‘mytype’ is ambiguous
mytype m = GetInt();
^
tmp.cpp:15:18: note: candidates are: typedef char B::mytype
typedef char mytype;
^
tmp.cpp:8:17: note: typedef int A::mytype
typedef int mytype;
^
tmp.cpp:27:16: error: expected ‘;’ before ‘m’
mytype m = GetInt();
As we can see from the code that GetInt() is defined only in the class A, so I though that mytype will be taken from class A only. But it is not the case as per the error log.
We can solve this by adding the scope of class A like
A::mytype m = GetInt();
I want to know about:
How compiler is behaving in this case?
Is there ant compiler flag that will solve this error in case of gcc?
[dcl.typedef]/p6
In a given scope, a typedef specifier shall not be used to redefine the name of any type declared in that
scope to refer to a different type
GetInt might be defined in A but the typedefs in the base classes will bring the conflict into play when resolving the name in scenario() (cfr. [class.member.lookup]) since this is an unqualified lookup.
This behavior is defined and expected. I'm not aware of any flag you might use to achieve your goal. Either go for a qualified name lookup as you've already discovered or use auto type deduction as Joachim pointed out.
Why does this not compile?
File.hpp
class CTest
{
public:
enum enumTest { EN_TEST };
//constructor:
CTest(enumTest f_en);
};
AnotherFile.hpp
#include "File.hpp"
class CAnotherTest
{
public:
CTest obj_Test(CTest::EN_TEST);
};
Visual Studio says: error C2061: syntax error : identifier 'EN_TEST'
armcc compiler says: error: #757: constant "CTest::EN_TEST" is not a type name
Thanks, Mirco
Because,
CTest obj_Test(CTest::EN_TEST);
is evaluated as a function named obj_Test. Now it should have argument as a type, however, CTest::EN_TEST is a value, not a type.
If it's intended that obj_Test an object then you have pass CTest::EN_TEST to it in the constructor:
class CAnotherTest
{
public:
CAnotherTest () : obj_Test(CTest::EN_TEST) {}
};
Because your syntax for CAnotherTest is wrong. Perhaps you mean something like this?
class CAnotherTest
{
public:
// Constructor vvv Initialise member variable
CAnotherTest() : obj_Test(CTest::EN_TEST) {}
// Member variable
CTest obj_Test;
};
You cannot initialize like that. In-class initialization can be done for only static const integral type.
Use initialization-list in the constructor, as:
class CAnotherTest
{
public:
CTest obj_Test; //member declaration. no initialization here
static const int value = 100; //OK. static const integral type!
CAnotherTest() : obj_Test(CTest::EN_TEST) {}
//^^^^^^^^^^^^^^^^^^^^^^^^^^ its called initialization-list
};
const int CAnotherTest::value; //definition goes to .cpp file