I define an enums using include,since there are different enums which have the same enumeration data and I want to reuse it:
#define X(SYM) SYM
#define X_INIT(SYM,VAL) SYM = VAL
/// Destination for scalar memory read instruction
enum SSRC
{
#include "GenericInstructionFields1.h"
#include "ScalarInstructionFields.h"
#include "GenericInstructionFields2.h"
};
enum SDST
{
#include "GenericInstructionFields1.h"
};
#undef X_INIT
#undef X
};
But I can`t compile the code for SDST. The compiler writes redefinition for a fields of SSRC,which comes from "GenericInstructionFields1.h". What is the cause of the problem and how can it be solved?
//GenericInstructionFields1.h
/// SGPR0 to SGPR103: Scalar general-purpose registers.
X_INIT(ScalarGPRMin,0),
X(ScalarGPR),
X_INIT(ScalarGPRMax,103),
/// 104 – 105 reserved.
X(Reserved104),
X(Reserved105),
X_INIT(Reserved,2),
/// vcc[31:0].
X_INIT(VccLo, 106),
/// vcc[63:32].
X(VccHi),
You can't have enumerations with the same enumerators in the same namespace. This would reproduce your problem:
enum X {A,B};
enum Y {A};
either use namespaces or prefix your enum values.
Enums are not like namespaces.
You will see the same error with the following
enum A
{
P, Q
};
enum B
{
P, Q
};
You can achieve what you want by this
struct A
{
enum { P, Q };
};
struct B
{
enum { P, Q };
};
You can now use A::P, A::Q, B::P & B::Q
Or in your case
#define X(SYM) SYM
#define X_INIT(SYM,VAL) SYM = VAL
/// Destination for scalar memory read instruction
struct SSRC
{
enum
{
#include "GenericInstructionFields1.h"
#include "ScalarInstructionFields.h"
#include "GenericInstructionFields2.h"
}
};
struct SDST
{
enum
{
#include "GenericInstructionFields1.h"
}
};
#undef X_INIT
#undef X
};
You can now use SSRC::ScalarGPRMax and SDST::ScalarGPRMax
Related
I have some C code that has some structs that looks like this:
typedef struct my_library_a_t my_library_a_t;
typedef struct my_library_b_t my_library_b_t;
typedef struct my_library_c_t my_library_c_t;
struct my_library_a_t {
struct my_library_b_t {
int data;
struct my_library_c_t {
int data;
} c;
} b;
int data;
};
This doesn't work in C++, because in C struct my_library_b_t defines a global struct my_library_b_t, whereas in C++ it defines ::my_library_a_t::my_library_b_t.
How can I get the inner struct definition to define a global struct in C++? Or even just not have to change too much code for it to work (I don't mind having a #ifdef __cplusplus block, but I don't want to pull the structs out because the reason they are nested in the first place is that they are used only one time each, and it's really hard to read when the inner class definitions are above the outer class definitions)
I tried struct ::my_library_b_t in the definition, but this doesn't work.
For context, I'm parsing a string that has a definition that would look like this:
a = b "," data
b = data "," c
c = data
data = %x31-39 *DIGIT ; 1-9 followed by *(0-9)
/ "0"
And the intermediate parts have meaning, so it's useful to be able to have functions that take my_library_b_t* or my_library_c_t*.
I would prefer to have a solution that looks like this:
#ifdef __cplusplus
#define GLOBAL_STRUCT(name) ??? (I tried `:: name`)
extern "C" {
#else
#define GLOBAL_STRUCT(name) name
#endif
struct my_library_a_t {
struct GLOBAL_STRUCT(my_library_b_t) {
// ...
I recommend this
struct my_library_a_t {
struct my_library_b_t {
int data;
struct my_library_c_t {
int data;
} c;
} b;
int data;
};
#ifdef __cplusplus
typedef struct my_library_a_t::my_library_b_t my_library_b_t;
typedef struct my_library_b_t::my_library_c_t my_library_c_t;
#else
typedef struct my_library_a_t my_library_a_t;
typedef struct my_library_b_t my_library_b_t;
typedef struct my_library_c_t my_library_c_t;
#endif
Notice that after alias my_library_b_t, you don't need to use my_library_a_t::my_library_b_t::my_library_c_t
enum class Fruit { apple, orange, pear };
enum class Color { red, green, orange };
template <typename T> struct Traits;
//I have to return the appropriate value(string) of color and fruit in their respective structs.
//I could do this by switch case method but I specifically wanted to know, how do I access an enum class through index
template<>
struct Traits<Fruit>{
static string name(int i){
if(i>-1&&i<3){
return Fruit::static_cast<Fruit>(i);
}
else{
return "unknown";
}
}
};
template<>
struct Traits<Color>{
static string name(int i){
if(i>-1&&i<3){
return Color::static_cast<Color>(i);
}
else{
return "unknown";
}
}
};
I want to return the appropriate string present in the respective structs at their respective indices.
The static_cast is not working and compiler is giving an error that it can't cast. I wonder if it is possible to access enum class through index at all.
Error:
could not convert ‘(Fruit)i’ from ‘Fruit’ to
‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’
return static_cast<Fruit>(i);
As error says you cannot directly convert enum class into string. But you can convert int into enum class using static_cast
After converting int into enum you can go ahead with enum to string conversion. There are many ways to do and this so answer has good summary of that
static string name(int i) {
if (i>-1 && i<3) {
Fruit f = static_cast<Fruit>(i);
return name(f);
}
else {
// return default value or throw error
return "";
}
}
static string name(Fruit f) {
//convert f and return string
}
You could have an array of fruit names in parallel to your enum to have names:
std::string FruitNames[] = { "apple", "orange", "pear" };
Now you can use this directly to get names from. If you are willing to invest a little into x-macros, you can generate both your array and the enum from with one single macro:
#define FRUITS GEN_FRUIT(apple) GEN_FRUIT(orange) GEN_FRUIT(pear)
#define GEN_FRUIT(X) X,
enum class Fruit { FRUITS };
#undef GEN_FRUIT
#define GEN_FRUIT(X) [Fruit::X] = #X,
std::string const FruitNames[] = { FRUITS };
#undef GEN_FRUIT
Admitted, harder to read, on the other hand, you have just one single location to maintain both enum and array...
You could even support explicit values:
#define FRUITS GEN_FRUIT_V(apple, 1) GEN_FRUIT(orange) GEN_FRUIT_V(pear, 4)
#define GEN_FRUIT(X) X,
#define GEN_FRUIT_V(X, Y) X = (Y),
enum class Fruit { FRUITS };
#undef GEN_FRUIT
#undef GEN_FRUIT_V
#define GEN_FRUIT(X) GEN_FRUIT_V(X, Fruit::X)
#define GEN_FRUIT_V(X, Y) std::make_pair(static_cast<Fruit>(Y), std::string(#X)),
std::unordered_map<Fruit, std::string> const FruitNames({ FRUITS });
// or (tree) map, if you prefer
//std::map<Fruit, std::string> const FruitNames({ FRUITS });
#undef GEN_FRUIT
#undef GEN_FRUIT_V
With upcoming C++20 (or a compiler supporting designated initialisers as extension), you could use an array again:
#define GEN_FRUIT(X) X,
#define GEN_FRUIT_V(X, Y) X = (Y),
enum class Fruit { FRUITS };
#undef GEN_FRUIT
#undef GEN_FRUIT_V
#define GEN_FRUIT(X) [static_cast<int>(Fruit::X)] = #X,
#define GEN_FRUIT_V(X, Y) GEN_FRUIT(X)
std::string const FruitNames[] = { FRUITS };
#undef GEN_FRUIT
#undef GEN_FRUIT_V
Yet future music... Result in above example would be an enum with gaps and the array filled with empty strings at the gaps. If gaps are large (or negative enum values exist), this approach would result in large array as well, so rather not appropriate any more, you might prefer falling back to the map solution again...
I have a class like this:
class TType {
public:
...
enum binary_type {
bt_a = 0,
bt_xyz,
....
bt_ak = 10,
....
};
}
and I use it in several places, also the enum:
if(var12 == TType::bt_a ) { ....
Now I imported a C library which has exactly the same enum (same keys, same values, same size) inside one of it's headerfiles:
typedef enum data_types_e {
bt_a = 0,
bt_xyz,
....
} data_types;
How can I define the enum in the c++ class definition to use the declaration of the c headerfile?
I want to continue using the enum the same way as before (TType::bt_a), and avoid copying the whole enum. Furthermore I don't wont to modify the library (otherwise a preprocessor-macro would do the trick) and I want changes made in the library also be made to the enum in my class.
Neither a typedef inside the c++ class definition nor a type alias (c++11) seem to work in this situation.
"How can I define the enum in the c++ class definition to use the declaration of the c headerfile?"
You can simply reuse the values from the c-style enum:
#include "TheOtherEnum.h"
...
enum binary_type {
bt_a = ::bt_a,
bt_xyz = ::bt_xyz,
....
bt_ak = ::bt_ak,
....
};
"Neither a typedef inside the c++ class definition nor a type alias (c++11) seem to work in this situation."
Yes these would work to provide the correct enum type, but you'll still need to qualify the values from the global namespace and not for nested to your class.
You can make C++ enum dependant of C enum:
typedef enum data_types_e {
bt_a = 0,
bt_xyz,
....
} data_types;
// ...
class TType {
public:
...
enum binary_type {
bt_a = bt_a,
bt_xyz = bt_xyz,
....
};
}
If possible, try renaming your class TType say, class TType_1.
//=============CLibraryFileContainingEnum.h=================
typedef enum data_types_e
{
bt_a = 9999,
bt_xyz
} data_types;
//==========================================================
//==========================================================
class TType_1
{
public:
enum binary_type
{
bt_a = 8878,
bt_xyz
};
};
namespace TType
{
#include "CLibraryFileContainingEnum.h"
}
int main()
{
int a = TType::bt_a; //this prints 9999
cout << a << endl;
return 0;
}
//==========================================================
Here is my answer, this is an old topic, but better lately than never
class TType {
public :
public:
...
#undef __cplusplus
#include "yourheaderc.h"
#define __cplusplus
}
maybe with a typedef binary_type data_types to preserve your nominations
But this solution is available if your header don't contains syntax C forbidden in C++. I'm currently searching a new solution because there are prototypes in my header that contains something like :
void afunction( unsigned long id,
enum T_TYPE type,
enum T_CHAR characteristic,
unsigned short number,
unsigned short value);
because T_TYPE and T_CHAR are not typedef-ed but this syntax is non-sense in C++ because it's the declaration syntax. So my solution is not appropriate if you are in a similar case.
The following sample does not compile, complaining that
In file included from /usr/include/msgpack.hpp:18:
/usr/include/msgpack/object.hpp:211:3: error: member reference base type 'logd::log_level' is not a structure or union
and a corresponding error for the other enum class. My question is how, using msgpack's c++ api, does one serialize a class with members that are of c++11 enum class type?
#ifndef LOG_MSG_HPP_
#define LOG_MSG_HPP_
#include <stdlib.h>
#include <msgpack.hpp>
/** #namespace logd */
namespace logd {
enum class log_level { SILENT,... DEBUG };
enum class log_domain { AI, ... MISC };
class log_msg {
public:
log_msg(log_level lev, log_domain dom, std::string msg);
log_level level();
log_domain domain();
std::string message();
~log_msg();
MSGPACK_DEFINE(lev_, dom_, msg_);
private:
log_msg();
log_level lev_ {log_level::DEBUG};
log_domain dom_ {log_domain::MISC};
std::string msg_ {"No message given."};
};
} /* namespace logd */
#endif /* LOG_MSG_HPP_ */
NOTE: Since the enums are mine, I can happily modify them to make msgpack happy. Unfortunately, I can find no references on the subject in their docs or the first couple pages of Google. I am also not able to determine what to do from reading their headers/source since I'm rather new to c++.
You can use MSGPACK_ADD_ENUM() macro. It has been supported since version 1.0.0. I recommend version 1.1.0 or later.
See:
https://github.com/msgpack/msgpack-c/wiki/v1_1_cpp_adaptor#enums
I applied MSGPACK_ADD_ENUM() to your code:
#ifndef LOG_MSG_HPP_
#define LOG_MSG_HPP_
#include <stdlib.h>
#include <msgpack.hpp>
/** #namespace logd */
namespace logd {
enum class log_level { SILENT,DEBUG };
enum class log_domain { AI, MISC };
class log_msg {
public:
log_msg(log_level lev, log_domain dom, std::string msg):lev_(lev), dom_(dom), msg_(msg) {}
log_level level() { return lev_;}
log_domain domain() { return dom_;}
std::string message() { return msg_; }
~log_msg() {}
MSGPACK_DEFINE(lev_, dom_, msg_);
log_msg() = default;
private:
log_level lev_ {log_level::DEBUG};
log_domain dom_ {log_domain::MISC};
std::string msg_ {"No message given."};
};
} /* namespace logd */
MSGPACK_ADD_ENUM(logd::log_level);
MSGPACK_ADD_ENUM(logd::log_domain);
#endif /* LOG_MSG_HPP_ */
#include <sstream>
#include <cassert>
int main() {
logd::log_msg lm { logd::log_level::SILENT, logd::log_domain::AI, "hello" };
std::stringstream ss;
msgpack::pack(ss, lm);
msgpack::object obj = msgpack::unpack(ss.str().data(), ss.str().size()).get();
logd::log_msg lm2 = obj.as<logd::log_msg>();
assert(lm.level() == lm2.level());
assert(lm.domain() == lm2.domain());
assert(lm.message() == lm2.message());
}
One way that seems to work is to wrap the enum in a union...
union log_level_t {
log_level lev;
int levint;
}
...
log_level_t lev_;
...
MSGPACK_DEFINE(lev_.levint, dom_.domint, msg);
This seems like a crappy approach, but it works.
I found another solution, maybe a little more elegant (ok, it's not so perfect):
MSGPACK_DEFINE((int&)lev_, (int&)dom_, msg)
So you can keep your original enum without creating a new union.
The deserialisation method should work without any problem.
According to the CERT standards Object-like macros can be dangerous because their uses are not subject to the language scope rules. Can any one please explain with an example How it is problematic. say for example I have an Object-like macro #define BUFFER_SIZE 1024
// file a.hpp
#define SOME_MACRO 42
// file some/nested/dir/really/far/in/x.hpp
#define SOME_MACRO 13
Kaboom. This would have easily been avoided using any kind of scope, e.g.
struct X { static unsigned const value = 42; };
struct Y { static unsigned const value = 13; };
Now you can access X::value and Y::value. Same goes for namespaces:
namespace a { struct X; }
namespace b { struct X; }
C/C++ preprocessing is just manipulating/generating text, no language rules involved.
A classic example is
#define max 1234
...
class A
{
int arr[100];
public:
...
int max() { ... find highest in arr ... }
};
This won't compile.