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;
Related
Is it possible to extract a static member type from the class of a local variable? aka something in the lines of
class A {
public:
typedef int constituent_type;
constituent_type a;
A(constituent_type _a) :a(_a) {};
}
int main() {
auto a = A(42);
// ... lots ... of other code; where I have long since forgottten, what the type of a really was
std::max<a::constituent_type>(a, a); //<<<
}
You can do that in C++ 11 or later using decltype:
decltype(a)::x
Live demo:
https://godbolt.org/z/cTq9zhKxe
I can do this
class Draw
{
public:
Draw();
static const Shape_f32 shape;
}
But what if I want to initilize the inner types of shape to a certain value? Like
shape.side.value = 5.0;
I tried to do these different solutions:
1.
class Draw
{
public:
Draw();
static const Shape_f32 shape.shape.value = 5.0;
}
class Draw
{
public:
Draw() {
shape.side.value = 5.0;
};
static const Shape_f32 shape;
}
I am not able to make any modifications to the type Shape_f32 here. So is what i want to do possible? It seems like I somehow need to create a type initializer that accepts a value.
Definition of Shape_f32
typedef struct Shape_f32_
{
PI_side side;
} Shape_f32;
typedef struct PI_side_
{
float value;
} PI_side;
You can use list initialisation:
inline static const Shape_f32 shape {
.side {
.value = 5.0,
},
};
Prior to C++20 however, you cannot use designated initialisers, and you need to initialise the members in order of their declaration instead.
P.S. If you define the static variable in a header, you should declare it inline in case you odr-use it.
For you case, simple initializer list outside class definition should be sufficient (if you know all of the fields inside Shape_f32)
#include <iostream>
#include <string>
typedef struct PI_side_
{
float value;
} PI_side;
typedef struct Shape_f32_
{
PI_side side;
} Shape_f32;
struct Foo{
public:
float get() {return bar_.side.value;}
private:
static const Shape_f32 bar_;
};
// definition outside the class, it would be best if this line is inside .cpp where you are using "Foo"
const Shape_f32 Foo::bar_ = {5};
int main() {
Foo var;
std::cout << var.get() << std::endl;
}
This normally outputs 5
edit: it also works for private/protected members
I want to write a function that return different types based on different input as below.
enum MyType
{
A,
B
};
template<MyType T> struct MyStruct
{
};
static auto createMyStruct(MyType t)
{
if(t==A)
return MyStruct<A>();
else
return MyStruct<B>();
}
It didn't work out because there are two return types for one auto. Is there any other way to do this?
There is absolutely no way of having a (single) function that returns different types based on a runtime decision. The return type has to be known at compile time. However, you can use a template function, like this (thanks to #dyp for making me simplify the code):
#include <iostream>
#include <typeinfo>
enum MyType
{
A,
B
};
template<MyType>
struct MyStruct {};
template<MyType type>
MyStruct<type> createMyStruct()
{
return {};
}
int main()
{
auto structA = createMyStruct<A>();
auto structB = createMyStruct<B>();
std::cout << typeid(structA).name() << std::endl;
std::cout << typeid(structB).name() << std::endl;
}
I am assuming you want to write code like this:
void foo (MyType t) {
auto x = createMyStruct(t);
//... do something with x
}
You are attempting to derive the right type for x at runtime. However, the return type of a function must be known at compile time, and the type resolution for auto is also determined at compile time.
You could instead restructure your code to be like this:
template<MyType T> struct MyStruct
{
//...
static void foo () {
MyStruct x;
//... do something with x
}
};
The idea is to write a single foo() function whose only difference is the type of thing it is manipulating. This function is encapsulated within the type itself. You can now make a runtime decision if you have a mapping between MyType and MyStruct<MyType>::foo.
typedef std::map<MyType, void(*)()> MyMap;
template <MyType...> struct PopulateMyMap;
template <MyType T> struct PopulateMyMap<T> {
void operator () (MyMap &m) {
m[T] = MyStruct<T>::foo;
}
};
template <MyType T, MyType... Rest> struct PopulateMyMap<T, Rest...> {
void operator () (MyMap &m) {
m[T] = MyStruct<T>::foo;
PopulateMyMap<Rest...>()(m);
}
};
template<MyType... Types> void populateMyMap (MyMap &m) {
PopulateMyMap<Types...>()(m);
}
//...
populateMyMap<A, B>(myMapInstance);
Then, to make a runtime decision:
void foo (MyType t) {
myMapInstance.at(t)();
}
I think you should learn abstract factory design pattern.
For use objects of type MyStruct<A> or MyStruct<B> you need common interface.
Common interface provided in abstract base class.
struct MyStruct
{
virtual ~MyStruct() {}
virtual void StructMethod() = 0;
};
struct MyStructA: public MyStruct
{
void StructMethod() override {}
};
struct MyStructB: public MyStruct
{
void StructMethod() override {}
};
std::unique_ptr<MyStruct> createMyStruct(MyType t)
{
if (t==A)
return std::make_unique<MyStructA>();
else
return std::make_unique<MyStructB>();
}
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;
};
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...