cannot convert anonymous enum in initialization - c++

Why does the compiler complain here?
enum jit_ptx_type {f32=0,f64=1,u16=2,u32=3,u64=4,s16=5,s32=6,s64=7,u8=8,b16=9,b32=10,b64=11,pred=12 };
//
// MATCHING C TYPES TO PTX TYPES
//
template<class T> struct jit_type {};
template<> struct jit_type<float> { enum { value = jit_ptx_type::f32 }; };
template<> struct jit_type<double> { enum { value = jit_ptx_type::f64 }; };
template<> struct jit_type<int> { enum { value = jit_ptx_type::s32 }; };
template<> struct jit_type<bool> { enum { value = jit_ptx_type::pred }; };
later in the code:
some_func( float val ) {
jit_ptx_type type = jit_type<float>::value; // compiler complains here
}
Compiler message:
error: cannot convert ‘jit_type<float>::<anonymous enum>’ to ‘jit_ptx_type’ in assignment
It's strange! If I put these lines into a separate small example file it works.

I'd go for making the outer enum into a scoped enum:
enum class jit_ptx_type {
f32=0, //note the =x is unnecessary here
f64=1,
u16=2,
u32=3,
u64=4,
s16=5,
s32=6,
s64=7,
u8=8,
b16=9,
b32=10,
b64=11,
pred=12
};
Now you don't pollute the surrounding scope with all of those identifiers and you need scope qualifiers to access the values, whereas unscoped enums disallow that. Next, in your class, just use a static constant member:
template<> struct jit_type<float> {
static constexpr value = jit_ptx_type::f32;
};

Related

Change default value initialization of scoped enum in C++ 20?

Is it possible to change the behavior of default value initialization of a scoped enum in C++ 20 ?
For exemple, in the following code, I'd like that a MyEnum variable to be initialized automaticatly with MyEnum::No when declared with MyEnum myValue{};
using MyEnumRootType = unsigned int;
using MyEnum = enum class EMyEnum: MyEnumRootType {
Yes = 0x1,
No = 0x2
};
int main() {
const MyEnum myValue{}; // <- 0
std::cout << static_cast<MyEnumRootType>(myValue);
}
edit:
I'v tried to write a wrapper like Benjamin Buch suggested (thanks).
I'm using template because I want it to be reusable.
I managed to handle a default value but I'm struggling to make it act like a real scoped enum (last line of main doesn't compile).
#include <concepts>
using MyEnumRootType = unsigned int;
enum class EMyEnum: MyEnumRootType {
Yes = 0x1,
No = 0x2
};
template<typename T>
concept ScopedEnum = std::is_enum_v<T> && !std::is_convertible_v<T, int>;
template<typename Enum, auto DefaultValue>
requires ScopedEnum<Enum>
class EnumWrapper{
public:
EnumWrapper(): value_(DefaultValue) {}
EnumWrapper& operator=(Enum e) { value_ = e; return *this; }
operator Enum() const { return value_; }
private:
Enum value_;
};
using MyEnum = EnumWrapper<EMyEnum, EMyEnum::No>;
int main() {
MyEnum a{};
MyEnum b = MyEnum::Yes; // how can I make this works ?
}
Can I do something like this in a template https://en.cppreference.com/w/cpp/language/enum#Using-enum-declaration ?
That's not possible directly for an enumeration (except if you are willing to change the value of No to 0x0). Enumerations are not class types (even if there is class in enum class), so you can't affect their behavior like you can with member functions/constructors/destructors/etc of classes.
Instead you'll have to make a class wrapper around it in which you can define a default constructor to do whatever you want.
It is only possible to write a wrapper class to achieve this behavior. Use using enum to address the values of your enumeration directly via the wapper class. Define a data member of the enumeration type and a cast operator for this type.
using MyEnumRootType = unsigned int;
enum class EMyEnum: MyEnumRootType {
Yes = 0x1,
No = 0x2
};
struct MyEnum {
using enum EMyEnum;
constexpr operator EMyEnum() const noexcept {
return value;
}
EMyEnum value = No;
};
int main() {
constexpr MyEnum myValue{};
static_assert(myValue != MyEnum::Yes);
static_assert(myValue == MyEnum::No);
static_assert(myValue != EMyEnum{});
}

Can an unnamed struct be made static?

Can you make an unnamed struct a static member of a class?
struct Foo
{
struct namedStruct
{
int memb1, memb2;
};
static namedStruct namedStructObj;
struct
{
int memb1, memb2;
} unnamedStructObj;
};
Foo::namedStruct Foo::namedStructObj;
// The unnamed type doesn't seem to have a type you can write
Yes, it's possible:
struct Foo
{
struct
{
int memb1, memb2;
} static unnamedStructObj;
};
decltype(Foo::unnamedStructObj) Foo::unnamedStructObj;
Here, as you don't have any way to reference the unnamed struct, using decltype(Foo::unnamedStructObj) makes it possible to retrieve the type of Foo::unnamedStructObj, so you can write the definition.
You can do it with the help of decltype():
struct Foo
{
struct namedStruct
{
int memb1, memb2;
};
static namedStruct namedStructObj;
static struct
{
int memb1, memb2;
} unnamedStructObj;
};
Foo::namedStruct Foo::namedStructObj;
decltype(Foo::unnamedStructObj) Foo::unnamedStructObj;

Using enums for type checking -- how to scope properly

I have a mixture of C++ classes, some of which store a state variable 0..9 as integer, others use '0' ... '9'. Currently I do:
enum { kOne = '1' };
class StoresValueAsInt {
static int value; // contains 0 ... 9
};
class StoresValueAsChar {
static char value; // contains '0' ... '9'
};
class StoresValueAsChar {
static char value;
};
template <typename X>
isOne() { return X::value == kOne; }
This allows me to write the buggy code isOne<StoresValueAsInt::value>(). Instead, I would like to have the compiler complain about this incorrect usage. I tried the following:
enum ValueInt {
kOne = 1
};
enum ValueChar {
kOne = '1'
};
class StoresValueAsInt {
static ValueInt value;
};
class StoresValueAsChar {
static ValueChar value;
};
class StoresValueAsChar2 {
static ValueChar value;
};
However, this does not work, because kOne is visible at the namespace level, and thus it has conflicting declarations of kOne.
Is there a way to not have the enums declared in the namespace? Or a better approach here?
updated: Added what I currently do; hoping to clarify my use case.
As far as best practice, I'm really not sure what you are trying to accomplish here so I can't point you in the right direction.
However, to answer your question directly: Placing the enums in seperate namespaces would solve your issue:
namespace IntVals {
enum ValueInt {
kOne = 1
};
}
namespace CharVals {
enum ValueChar {
kOne = '1'
};
}
class StoresValueAsInt {
static ValueInt value;
};
class StoresValueAsChar {
static ValueChar value;
};
Then you should be able to use the following:
StoresValueAsInt::value == CharVals::kOne
Though this is ugly, and I wish I understood better what you were going for to offer a more elegant solution than this.
Is there a way to not have the enums declared in the namespace? Or a better approach here?
Yes, you can differentiate your enums as below:
struct ValueInt {
enum { // no need to have enum Name
kOne = 1
};
};
struct ValueChar {
enum { // no need to have enum Name
kOne = '1'
};
};
Usage:
ValueInt::kOne;
ValueChar::kOne;

C++ error enum and CRTP

template<class T>
struct broker
{
typedef T typeBroker;
static std::vector<std::string> extractListBroker(const std::string& broker)
{
std::vector<std::string> vec;
if(broker.empty())
{
for(int i=0;i<typeBroker::nbBroker;++i)
vec.push_back( typeBroker::listBroker[i] );
}
else
{
typedef boost::tokenizer<boost::char_separator<char> > my_tok;
boost::char_separator<char> sep( ";" );
my_tok tok( broker, sep );
for ( my_tok::const_iterator i = tok.begin(); i != tok.end(); ++i )
vec.push_back( *i );
}
return vec;
}
std::string brokerToStr(typename typeBroker::BROKER i) //<--Problem here !!
{
return typeBroker::listBroker[i];
}
};
struct brokerDisTradable : broker<brokerDisTradable>{
std::vector<std::string> listBroker;
brokerDisTradable()
{
listBroker.push_back("BRIDGE1" );
listBroker.push_back("BRIDGELONDON" );
listBroker.push_back("RECY" );
listBroker.push_back("CURRENEX" );
}
static const int nbBroker = 2;
enum BROKER { BRIDGE1, BRIDGELONDON, RECY, CURRENEX };
};
errro : error C2039: 'BROKER' : is not a member of broker_def::brokerDisTradable'
any idea?
Thanks!
You cannot use the derived type's internal types in the function declaration of the base, because the derived type's internal types aren't yet defined, the derived type is only declared.
There are a number of ways to get around this, including type traits parameter and additional template parameter, and they are perfectly discussed in Base's using a type defined in Derived, in a Curiously Recurring Template Pattern of comp.lang.c++.moderated: http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/a99148265cb43680/b2581e058ffe8c91?#b2581e058ffe8c91
Since you're using the enum value as an index into an array, you could change the parameter type to brokerToStr to an int:
struct broker
{
typedef T typeBroker;
std::string brokerToStr(int i)
{
return typeBroker::listBroker[i];
}
Also, typeBroker::listBroker[i] won't work as listBroker is not a static member.
I don't understand why you are inheriting brokerDisTradable from border<brokerDisTradable>. Probably what you need to do is this:
struct brokerDisTradable {
std::vector<std::string> listBroker;
brokerDisTradable()
{
// ...
}
static const int nbBroker = 2;
enum BROKER { BRIDGE1, BRIDGELONDON, RECY, CURRENEX };
};
int main()
{
brokerDisTradable t;
broker<brokerDisTradable> b;
// ...
return 0;
}
A simplified example of the problem:
template <class T>
struct X
{
void foo(typename T::Enum);
};
struct Y: X<Y> //<-- X instantiate here, but at this point the compiler only knows
//that a struct called Y exists, not what it contains
{
enum Enum {Z};
};
As a possible workaround, perhaps move the enumeration out of Y and add a template parameter to X.
template <class T, class EnumType>
struct X
{
void foo(EnumType);
};
enum Y_Enum {Z};
struct Y: X<Y, Y_Enum>
{
};
brokerDisTradable : broker<brokerDisTradable> seems to be an incomplete type (infinite heritage inside)
struct brokerDisTradable and using broker<brokerDisTradable> will work..

comparing enum from templated class - is it safe?

So, a simple question really, illustrated by the example below. When you compile this, the compiler appropriately(?) reports a warning (that we are comparing barfoo<int>::bar with barfoo<foo>::bar), now given bar is an enum - can I safely ignore this warning?
#include <iostream>
using namespace std;
struct foo
{
};
template <typename bob = int>
struct barfoo
{
enum bar { ONE, TWO, THREE };
bar action() const { return TWO; }
};
template <barfoo<>::bar eAction = barfoo<>::ONE>
struct IsAction
{
template <typename bf>
static bool check(bf const& cState)
{
return cState.action() == eAction;
}
};
int main(void)
{
barfoo<foo> c;
cout << IsAction<>::check(c) << endl;
return 0;
}
Given I'm a stickler for removing warning messages, is there a way to satisfy the compiler without moving the enum outside?
The numeric representation of the enums will be the same, so it's safe to compare them directly (or even cast between them, although you may need to go through int to satisfy the compiler). If you want to silence the warning, one approach would be to cast them both to ints before doing the comparison: (int)cState.action == (int)eAction. You might be able to add a templated operator== for the enum to do this automatically - not sure on this point, though.
Alternately, depending on how you define "without moving the enum outside", you could derive from a non-templated base class that serves to hold the enum's definition, as in http://codepad.org/8bVlcas3
I would move it outside but to a base-class:
struct barenum
{
enum bar { ONE, TWO, THREE };
protected: // because we are going to derive from it without a virtual destructor
~barenum() {}
};
template <typename bob = int>
struct barfoo : barenum
{
bar action() const { return TWO; }
};
does moving the enum into a parent of barfoo count?
#include <iostream>
using namespace std;
struct foo
{
};
struct barfoobase
{
enum bar { ONE, TWO, THREE };
};
template <typename bob = int>
struct barfoo : public barfoobase
{
bar action() const { return TWO; }
};
template <barfoobase::bar eAction = barfoobase::ONE>
struct IsAction
{
template <typename bf>
static bool check(bf const& cState)
{
return cState.action() == eAction;
}
};
int main(void)
{
barfoo<foo> c;
cout << IsAction<>::check(c) << endl;
return 0;
}
edit:
Oops, that answer has already been posted...