I have a few enums in my program and I want to share it across different classes.
When I tried to define it in each class I got a "redefining" error.
Then I searched Google and saw that I should put it in a different header.
I tried to to do that and included the header into every class header - I still got the same error.
Searched some more and found in StackOverflow a thread saying I should put them in their own namespace.
So I tried:
enum.h:
namespace my_enums
{
enum classification {DATA_STORAGE,DMS,E_COMMERCE,GAMING,RTES,SECURITY};
enum skill { CPP, JAVA, SCRIPT, WEB, SYSTEM, QA };
enum company_policy {CHEAP, LAVISH, COST_EFFECTIVE};
}
But that still doesn't work: First, if tell classes that include the header to: "using namespace my_enums;" I get " is ambiguous" error.
What is the correct way to do what I'm trying to do?
Thanks in advance ^_^
Did you remember the multiple inclusion guard? Normally looks like:
#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H
[...code...]
#endif
and protects types and enums from getting defined multiply in a compilation unit.
You only need to declare your enums once in a header if you wish and include that header where you use the enums:
//enum.h:
//include guards:
#ifndef MY_ENUMS
#define MY_ENUMS
namespace my_enums
{
enum classification {DATA_STORAGE,DMS,E_COMMERCE,GAMING,RTES,SECURITY};
enum skill { CPP, JAVA, SCRIPT, WEB, SYSTEM, QA };
enum company_policy {CHEAP, LAVISH, COST_EFFECTIVE};
}
#endif
//A.h
#include "enum.h"
class A
{
void check()
{
my_enums::skill val = my_enums::SCRIPT;
}
};
Maybe you've included it more then once?
Don't forget to add "guards" on include
#ifndef MY_ENUM_H_
#define MY_ENUM_H_
.... enter your enums here ...
#endif // MY_ENUM_H_
struct Classification
{
enum Enum{ dataStorage, dms, eCommerce, gaming, rtes, security }
};
struct Skill
{
enum Enum{ cpp, java, script, web, system, qa };
};
struct CompanyPolicy
{
enum Enum{ cheap, lavish, cost_effective };
};
void whatever( Classification::Enum classification ) {}
class A
: protected Classification
{
public:
void foo() { whatever( dataStorage ); }
};
class B
{
public:
void foo() { whatever( Classification::dataStorage ); }
};
Related
Current Problem:
I need to access an enum from a class that is forward declared, similar to this situation:
Human.h
#include "Dog.h"
class Human{
public:
enum Language: uint32_t {
None = 0,
English = 1,
Japanese= 2,
};
}
Dog.h
class Human;
class Dog{
void understand(Human::Language speech);
}
Dog.cxx
#include "Dog.h"
#include "Human.h"
void Dog::understand(Human::Language speech) {
// Do stuff with Human::Language
return;
}
Errors:
The IDE tells me Dog.cxx's implementation is not compatible with Dog.h's deceleration, citing the enum as <erro-type> in the error hint (only red squiggle)
When compiling, any mention of the enum in Dog.h/c.xx throws errors, not being able to find the enum
Extra Info:
MSVC 15 2017
Full architecture of program requires the enum to be accessible like this
Forward Deceleration is mandatory in order to solve a circular dependency within my program that is not seen here
Basically the answer is no, you can't forward declare the enum in this context. Your choices are:
Move the enum into a lightweight base class.
struct HumanBase
{
enum Language: uint32_t {
None = 0,
English = 1,
Japanese= 2,
};
};
//fwd declare
struct Human;
Move the enum out of the class.
enum HumanLanguage : uint32_t {
None = 0,
English = 1,
Japanese= 2,
};
struct Human;
and then if you need to later on, you can do:
struct Human
{
typedef HumanLanguage Language;
};
Change all the method that use the enum to be a template (which may work in some cases, possibly not in others)
class Dog{
template<typename LanguageType)
void understand(LanguageType speech);
};
I want to be able to use an enum class that is defined in one file, and used in others. When I try I only get this error: enum "Animal" has no member "Lion"
I can't find any posts that answer my question.
Here is an example of what I have in mind:
zooanimals.h
#pragma once
namespace Zoo
{
enum class Animal;
}
zooanimals.cpp
#include "zooanimals.h"
namespace Zoo
{
enum class Animal
{
Lion,
Elefant,
Monkey
};
}
zoo.h
#pragma once
namespace Zoo
{
class Visitor;
}
zoo.cpp
#include "zoo.h"
#include "zooanimals.h"
namespace Zoo
{
class Visitor
{
Animal favoriteAnimal = Animal::Lion;
};
}
You don't split enums in declaration and definition, so
enum class Animal
{
Lion,
Elefant,
Monkey
};
should be in the header, not in a source file.
Remember, when you include a header into a source file, this source file can only "see" what is declared in this header. In your case, when the compiler processes zoo.cpp, it can not "see" the values of Animal, because they are not in the header.
Currently I am writing a class that supports data proccessing on the cpu or gpu utilizing preprocessor definitions to determine which header file to include.
IE
#ifdef CPU_work
#include "cpu_backend.h"
#endif
#ifdef GPU_work
#include "gpu_backend.h"
#endif
class Work {
//Implementation dependant upon included header
}
However, there maybe instances where I would need both variants. Is there anyway I could do something like....
namespace CPU {
#define CPU_work
//Generate implementation of WorkClass with cpu_backend.h
}
namespace GPU {
#define GPU_work
//Generate implementation of WorkClass with gpu_backend.h
}
and therefor determine which implementation I want via something like...
CPU::Work cpuObject;
GPU::Work gpuObject;
Would be happy with any work-arounds also.
Much thanks JJ.
This might be the place to use a template method design. Your base class implements everything that is common to both CPU and GPU and then you use abstract functions where there are differences.
class Work {
public:
void execute() {
// Do some initializing
foo();
// Do some middle stuff
bar();
// Do some final stuff
}
private:
virtual void foo() = 0;
virtual void bar() = 0;
}
class CpuWork: public Work {
virtual void foo() {
// Do some CPU stuff
}
virtual void bar() {
// Do some more CPU stuff
}
}
class GpuWork: public Work {
virtual void foo() {
// Do some GPU stuff
}
virtual void bar() {
// Do some more GPU stuff
}
}
You now can't use your base class Work by accident since it's abstract and you can't accidentally invoke your derived classes foo or bar since they are private members of the base class.
Interesting question:) If I understood your goals correct, I can suggest a few solutions.
First uses template specialization, template default arguments and (of course) some macros.
Check this out:
// cpu_backend.h
#define CPU_BACKEND
class UseCPU;
#ifndef GPU_BACKEND
template<class Method = UseCPU>
struct Backend;
#endif
template<>
struct Backend<UseCPU>
{
char* Info() { return "CPU"; }
};
// gpu_backend.h
#define GPU_BACKEND
class UseGPU;
#ifndef CPU_BACKEND
template<class Method = UseGPU>
struct Backend;
#endif
template<>
struct Backend<UseGPU>
{
char* Info() { return "GPU"; }
};
// main.cpp
// Try to swap comments on headers
// and see how output changes
#include "cpu_backend.h"
//#include "gpu_backend.h"
#include <iostream>
template<class ... Method>
struct Work
{
Work()
{
std::cout << "I use " << backend.Info() << std::endl;
}
private:
Backend<Method ...> backend;
};
int main()
{
Work<> work;
// Uncomment these two while including both headers
//Work<UseCPU> cpuWork;
//Work<UseGPU> gpuWork;
return 0;
}
If you use MSVC you can simplify example above eliminating #define and #ifndef.
Trick: MSVC (2017 and maybe earlier versions) allow to omit that macros thresh, just ignoring the second declaration if they meet in
the same compilation unit, like this:
template<class Method = UseCPU>
struct Backend;
template<class Method = UseGPU>
struct Backend;
BUT this will be not standard. Standard does not allow specifying default template args twice.
Meanwhile, this solution has few drawback:
When you include both headers, someone still can say Work<> which will
use the backend specified by the first header you included.
However, it would be better if compiler forced a person to specify a
backend type explicitly in this circumstances, because otherwise it
relies on the header inclusion order which is bad (say hello to
macros).
Also, it assumes that both backends have the same API (like Info()
in my case)
Possible Fixes for those:
I am sure it is possible to make compiler give an error when both
headers are included and no explicit backend was specified, but it
probably involves more preprocessor things or some SFINAE...
If your backends do have different APIs, then you can insert a few
#ifdef where needed or (preferably) use C++17
if constexpr(std::is_same<Method, UseCPU>()::value) if you have access
to such cool features:)
I have a couple functions that I want to use in many different classes. I have a couple classes that are derived from one base class and so tried to make it so that the base class held the functions and then the child classes could just call them. This seemed to cause linking errors, and so following advice from this question (Advantages of classes with only static methods in C++) I decided to give namespaces a swing, but the only file that is included by every header/file is resource.h, and I don't want to put a namespace for my functions in there as it seems to specialised to mess with.
My question is, how do I make a class that only includes a namespace, or the functions I want to use, so that I can just include this class and use the functions as desired?
Thank you in advance for the help, the answers I've found on the internet only focus on one file, not multiple files like I'm hoping to address :)
You seem confused about how namespaces are used. Here are some things to keep in mind when working with namespaces:
You create a namespace using the syntax namespace identifier { /* stuff */ }. Everything between the { } will be in this namespace.
You cannot create a namespace inside a user-defined type or function.
A namespace is an open group construct. This means you can add more stuff into this namespace later on in some other piece of code.
Namespaces aren't declared unlike some of the other language constructs.
If you want certain classes and/or functions inside a namespace scope, enclose it with the namespace syntax in the header of where it's defined. Modules using those classes will see the namespace when the headers get #include'd.
For example, in your Entity.h you might do:
// Entity.h
#pragma once
namespace EntityModule{
class Entity
{
public:
Entity();
~Entity();
// more Entity stuff
};
struct EntityFactory
{
static Entity* Create(int entity_id);
};
}
inside your main.cpp you access it like this:
#include "Entity.h"
int main()
{
EntityModule::Entity *e = EntityModule::EntityFactory::Create(42);
}
If you also want Player to be inside this namespace then just surround that with namespace EntityModule too:
// Player.h
#pragma once
#include "Entity.h"
namespace EntityModule{
class Player : public Entity
{
// stuff stuff stuff
};
}
This works because of point #3 above.
If for some reason you feel you need to create a namespace inside a class, you can simulate this to an extent using nested classes:
class Entity
{
public:
struct InnerEntity
{
static void inner_stuff();
static int more_inner_stuff;
private:
InnerEntity();
InnerEntity(const InnerEntity &);
};
// stuff stuff stuff
};
Some important differences and caveats doing it this way though:
Everything is qualified with static to indicate there's no specific instance associated.
Can be passed as a template parameter.
Requires a ; at the end.
You can't create a convenient shorthand with abusing namespace Entity::InnerEntity;. But perhaps this is a good thing.
Unlike namespaces, class and struct are closed constructs. That means you cannot extend what members it contains once defined. Doing so will cause a multiple definition error.
You can put anything in a namespace, but you can't put namespaces inside things ( that's not a very formal way of saying it but I hope you get what I mean.
Valid
namespace foospace
{
class foo
{
public :
foo();
~foo();
void eatFoo();
};
}
Invalid
namespace foospace
{
class foo
{
public :
foo();
~foo();
namespace eatspace
{
void eatFoo();
}
};
}
I'm not 100% certain that the second example wouldn't compile, but regardless, you shouldn't do it.
Now, from your comments it sounds like you want something like this :
In the file Entity.h, your entity class definition :
namespace EntitySpace
{
class Entity
{
public :
Entity();
~Entity();
};
}
In the file Player.h
#include "Entity.h"
namespace EntitySpace
{
class Player : public Entity
{
public :
Player();
~Player();
};
}
In the file main.cpp
#include "Player.h"
int main()
{
EntitySpace::Player p1;
EntitySpace::Player p2;
}
So you call upon Player in the EntitySpace namespace. Hope this answers what you were asking.
The error I get is "No member named detail in namespace ChessGame. Here is the relevant code
//ChessPiece.h
namespace ChessGame
{
class ChessBoard;
namespace detail
{
class IChessPieceEnums{
public:
enum PieceType{PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING};
enum PieceDirection{ UP = 1 , DOWN = -1};
enum PieceId{ WHITE_PIECE_ID, BLACK_PIECE_ID };
};
}
//represents an abstract chess piece interface
class IChessPiece : public detail::IChessPieceEnums
{
public:
///...
}
} // end namespace
//GameBoard.h
#include "ChessPiece.h"
namespace ChessGame
{
class IChessPiece;
class ChessBoard
{
public:
/*********ERROR OCCURS ON THIS FUNCTION************/
bool isOccupiedWithEnemy(int row, int col,const ChessGame::detail::IChessPieceEnums::PieceId& pieceId);
}
}
Any idea guys?
EDIT: Another minimal example :
//Piece.h
#ifndef TestProject_C___Piece_h
#define TestProject_C___Piece_h
#include "Board.h"
namespace Foo {
namespace detail{
struct PieceEnums{
enum PieceID{ ID1, ID2 };
};
}
class Board;
class Piece{
public:
void foo(Board& b)const;
};
}
#endif
//board.h
#ifndef TestProject_C___Board_h
#define TestProject_C___Board_h
#include "Piece.h"
namespace Foo {
class Piece;
class Board{
bool isOcc(int x, int y,const detail::PieceEnums::PieceID pid)const;
};
}
#endif
And the error is 'Use of undeclared identifier detail
Note that this is across multiple files, so maybe its a problem with linkage?
To specify the desired name directly, say either detail::IChessPieceEnums::PieceId or ::ChessGame::detail::IChessPieceEnums::PieceId, but preferably the former. However, your present syntax is actually fine, too, since search resumes in the global namespace if a name can't be found.
Ok found a solution. The solution is to put the namespace detail in its own file called detail.h. That way, piece.h and board.h needs to include details.h to use it. That worked.
And the problem with the original post is that there is a circular reference. That is causing trouble somehow. Would love an explanation.