Can this be done?
enum A
{
enum B
{
SOMETHING1,
SOMETHING2
};
enum C
{
SOMETHING3,
SOMETHING4
};
};
If not is there an alternative solution?
The purpose of this question: Want/need to be able to do something like this:
enum class ElementaryParticleTypes
{
enum class MATTER
{
enum class MESONS
{
PI
};
enum class BARYONS
{
PROTON,
NEUTRON
};
enum class LEPTONS
{
ELECTRON
};
};
enum class ANTI_MATTER
{
enum class ANTI_MESONS
{
ANTI_PI
};
enum class ANTI_BARYONS
{
ANTI_PROTON
ANTI_NEUTRON
};
enum class ANTI_LEPTONS
{
POSITRON
};
};
};
Wish to use the strongly-typed capabilities.
No, they cannot be nested that way. In fact, any compiler would reject it.
If not is there an alternative solution?
That mostly depends on what you are trying to achieve (solution to what problem?). If your goal is to be able to write something like A::B::SOMETHING1, you could just define them within a namespace, this way:
namespace A
{
enum B
{
SOMETHING1,
SOMETHING2
};
enum C
{
SOMETHING3,
SOMETHING4
};
}
Seeing that in this particular case, the enumerations aren’t likely to change often, you could go for:
namespace ParticleTypes {
namespace Matter {
enum Mesons {
Pi
};
enum Baryons {
Proton = Pi + 1,
Neutron
};
enum Leptons {
Electron = Neutron + 1
};
}
namespace AntiMatter {
enum AntiMesons {
AntiPi = Matter::Electron + 1
};
// ...
}
}
I do wonder, however, why you want different enum types for different types of particles. Do you have functions which accept an argument of type Mesons, but not of type Leptons? If not, and all your functions accept any of the particles, then use a single enum – and preferably, drop the long prefixes to the names of the values like MATTER_MESONS_, MATTER_BARYONS_ etc.
MESONS pi = PI();
MATTER mat = pi;
assert (pi == mat);
Do you mind a little C++11 template magic?
template <typename T, typename... L>
struct is_defined_in : std::false_type {};
template <typename T, typename U, typename... L>
struct is_defined_in<T, U, L...> : is_defined_in<T, L...> {};
template <typename T, typename... L>
struct is_defined_in<T, T, L...> : std::true_type {};
template <int ID> struct helper {
friend bool operator==(helper a, helper b)
{ return a.id == b.id; }
friend bool operator!=(helper a, helper b)
{ return a.id != b.id; }
int id=ID;
};
template <typename... B> struct category {
int id;
template <typename T,
typename = typename std::enable_if<is_defined_in<T, B...>::value>::type>
category(T t) : id(t.id) {}
friend bool operator==(category a, category b)
{ return a.id == b.id; }
friend bool operator!=(category a, category b)
{ return a.id != b.id; }
};
enum class ElementaryParticleTypesID
{ PI, PROTON, NEUTRON, ELECTRON };
struct PI : helper<(int)ElementaryParticleTypesID::PI> {};
struct PROTON : helper<(int)ElementaryParticleTypesID::PROTON> {};
struct NEUTRON : helper<(int)ElementaryParticleTypesID::NEUTRON> {};
struct ELECTRON : helper<(int)ElementaryParticleTypesID::ELECTRON> {};
using MESONS = category<PI>;
using BARYONS = category<PROTON, NEUTRON>;
using LEPTONS = category<ELECTRON>;
using MATTER = category<MESONS, BARYONS, LEPTONS>;
(the static_assert currently doesn't work beyond two hierarchies, but this can be added if you want to)
No, there is no way of doing this without defining everything in a long list inside one enum.
enum class A{
PARTICLE_MATTER_BARYON_PROTON,
PARTICLE_MATTER_BARYON_NEUTRON,
PARTICLE_ANTIMATTER_BARYON_PROTON // etc
};
If this doesn't make sense to you, then you are surely a physicist.
I am accepting this as the answer to stop further notifications from stackoverflow asking me to accept an answer.
Related
I have a number of data types, which have some metadata related to them, say table_size and format. I want to get this metadata using a template lookup, i.e
struct C1
{}
struct C2
{}
enum class Format
{
Format1,
Format2,
};
template<typename T, int A, Format F>
class DataTypeMeta
{
constexpr int table_size = A;
constexpr Format data_format = F;
};
class Bar
{
public:
void Configure(Format f, int sz);
template<typename T>
void UploadData(std::vector<T> data){...}
}
template<typename T>
Bar foo(vector<T> data)
{
Bar obj;
obj.Configure(DataTypeMeta<T>::format, DataTypeMeta<T>::table_size);
obj.UploadData(data);
return obj;
}
int main()
{
std::vector<C1> data;
foo(data);
}
How can I implement this DataTypeMeta class or specialize it for the type C1, C2 etc
you seem to want to implement traits in some way:
see
https://accu.org/index.php/journals/442
http://www.info.univ-angers.fr/~richer/ens/div/traits_et_policy.php
http://www.bogotobogo.com/cplusplus/template_specialization_traits.php
for more explanation (or search about traits)
I have two(multiple) enums:
enum Choices1 : int
{
a,
b
};
enum Choices2 : int
{
c,
d
};
I want to be able to associate a Type to each of these enum choices. If I only had one set of enums say Choices1, I could introduce:
template <Choices1 c>
struct choice_traits;
and then specialise it for each entry:
template <>
struct choice_traits<Choices1::a>
{
using MyType = float;
};
template <>
struct choice_traits<Choices1::b>
{
using MyType = double;
But I want to be able to do it for multiple enums, while using the same keyword, ie something like:
template <>
struct choice_traits<Choices1::a>
{...};
template <>
struct choice_traits<Choices1::b>
{...};
template <>
struct choice_traits<Choices2::c>
{...};
template <>
struct choice_traits<Choices2::d>
{...};
Is this possible? if so, what would be the non specialised case?
If not, is there any alternative way of associating a Type to each of (Choice1::a,Choice1::b,Choice2::c,Choice2::d) and potentially more such enums?
Not a great solution but... you can use the common base (int) for Choiches1 and Choiches2 and define the not specialized case as
template <int>
struct choice_traits;
At this point the problem is that Choiches1::a == Coiches2::c and Choiches1::b == Choiches2::d so, if you want define something like
template <>
struct choice_traits<Choices1::a>
{ using MyType = float; };
template <>
struct choice_traits<Choices1::b>
{ using MyType = double; };
template <>
struct choice_traits<Choices2::c>
{ using MyType = int; };
template <>
struct choice_traits<Choices2::d>
{ using MyType = long; };
yuo have to avoid collisions between Choiches1 and Choiches2 values.
If you know the number of Choiches1 values, you can start Choiches2 with a bigger number; by example, if you're sure that there are minus than 100 Choiches1 values, you can define the enums as follows
enum Choices1 : int
{ a = 0, b };
enum Choices2 : int
{ c = 100, d };
Another solution can be use even and odd values for the two enums; something like
enum Choices1 : int
{ a = 0, b = a+2 }; // add 2 for every next value
enum Choices2 : int
{ c = 1, d = c+2 }; // add 2 for every next value
The following is a full example
enum Choices1 : int
{ a = 0, b };
enum Choices2 : int
{ c = 100, d };
template <int>
struct choice_traits;
template <>
struct choice_traits<Choices1::a>
{ using MyType = float; };
template <>
struct choice_traits<Choices1::b>
{ using MyType = double; };
template <>
struct choice_traits<Choices2::c>
{ using MyType = int; };
template <>
struct choice_traits<Choices2::d>
{ using MyType = long; };
int main()
{
choice_traits<a>::MyType fl { 1.1f };
choice_traits<b>::MyType db { 2.2 };
choice_traits<c>::MyType in { 3 };
choice_traits<d>::MyType ln { 4L };
}
Here is some excessive solution:
template <class Enum, Enum e>
struct choice_traits;
template<>
struct choice_traits<Choices1, Choices1::b>
{
typedef float MyType;
};
//using
typename choice_traits<Choices1, Choices1::b>::MyType m {0.0};
Now I have a template class
template <class T>
class b
{
void someFunc() {
T t;
t.setB();
}
};
I know the template T only will be instantiated into 2 classes.
class D
{
public:
void setB();
};
class R
{
public:
void SetB();
};
As we can see, class D's function name setB is not the same as R's function SetB. So in template class b I cannot only just use setB. So is there some method if I cannot revise D or R? Can I add some wrapper or trick into the template class to solve this problem?
Maybe a trait class can help you:
struct Lower {};
struct Upper {};
// trait for most cases
template <typename T>
struct the_trait {
typedef Lower Type;
};
// trait for special cases
template <>
struct the_trait<R> {
typedef Upper Type;
};
template <class T>
class b {
public:
void foo() {
foo_dispatch(typename the_trait<T>::Type());
}
private:
void foo_dispatch(Lower) {
T t;
t.setB();
}
void foo_dispatch(Upper) {
T t;
t.SetB();
}
};
As #Arunmu pointed, this technique is also known as Tag Dispatching.
You can specialise your template for the class that has different semantics:
template<>
class b<R>
{
void doWork() {
R obj;
obj.SetB();
// or R::SetB() if it was a static method.
}
};
Instead of using self programmed traits you can also check for the existence of a function with SFINAE.
If you want to switch your called method only one of them must exist in each class. My method provided will not work if the check find more then one of the tested methods!
The following example is written for C++14 but can also be used with c++03 if you replace the new library functions with self implemented ones ( which is of course not convenient )
The testing class has_Foo and has_Bar can also be embedded in a preprocessor macro, but I wrote it expanded to makes the things easier to read.
How it works and why there are some more intermediate steps are necessary are explained in the comments. See below!
#include <iostream>
// First we write two classes as example. Both classes represents
// external code which you could NOT modify, so you need an
// adapter to use it from your code.
class A
{
public:
void Foo() { std::cout << "A::Foo" << std::endl; }
};
class B
{
public:
void Bar() { std::cout << "B::Bar" << std::endl; }
};
// To benefit from SFINAE we need two helper classes which provide
// a simple test functionality. The solution is quite easy...
// we try to get the return value of the function we search for and
// create a pointer from it and set it to default value nullptr.
// if this works the overloaded method `test` returns the data type
// one. If the first test function will not fit, we cat with ... all
// other parameters which results in getting data type two.
// After that we can setup an enum which evaluates `value` to
// boolean true or false regarding to the comparison function.
template <typename T>
class has_Foo
{
using one = char;
using two = struct { char a; char b;};
template <typename C> static one test( typename std::remove_reference<decltype(std::declval<C>().Foo())>::type* );
template <typename C> static two test( ... ) ;
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
enum { Yes = sizeof(test<T>(0)) == sizeof(one) };
enum { No = !Yes };
};
template <typename T>
class has_Bar
{
using one = char;
using two = struct { char a; char b;};
template <typename C> static one test( typename std::remove_reference<decltype(std::declval<C>().Bar())>::type* );
template <typename C> static two test( ... ) ;
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
enum { Yes = sizeof(test<T>(0)) == sizeof(one) };
enum { No = !Yes };
};
// Now in your adapter class you can use the test functions
// to find out which function exists. If your class
// contains a Foo function the first one compiles and if the
// the class contains a Bar function the second one fits. SFINAE
// disable the rest.
// We need a call helper here because SFINAE only
// fails "soft" if the template parameter can deduced from the
// given parameters to the call itself. So the method
// Call forwards the type to test "T" to the helper method as
// as explicit parameter. Thats it!
template <typename T>
class X: public T
{
public:
template < typename N, std::enable_if_t< has_Foo<N>::value>* = nullptr>
void Call_Helper() { this->Foo(); }
template < typename N, std::enable_if_t< has_Bar<N>::value>* = nullptr>
void Call_Helper() { this->Bar(); }
void Call() { Call_Helper<T>(); }
};
int main()
{
X<A> xa;
X<B> xb;
xa.Call();
xb.Call();
}
I want to check if the type given to a template is inherited from a base class in my project.
It should work like one would expect it from the following example:
template< class T : public CBaseClass >
Is it possible to do this with templates, if not, how else can I do it?
Following an example from Stroustrup:
template<class Test, class Base>
struct AssertSameOrDerivedFrom {
AssertSameOrDerivedFrom() { &constraints; }
public:
static void constraints() {
Test *pd = 0;
Base *pb = pd;
}
};
template<class T>
struct YourClass {
YourClass() {
AssertSameOrDerivedFrom<T, CBaseClass>();
}
};
In C++0x, this becomes:
template<class T>
struct YourClass {
static_assert(std::is_base_of<CBaseClass, T>::value);
};
You can use boost::is_base_and_derived from Boost, combined with BOOST_STATIC_ASSERT. If you are using a compiler with TR1 or C++0x support, there are equivalents of those constructs in the standard library (std::is_base_of, and the static_assert statement in C++0x).
If you want to assert, do it Nurk's way. If you want to check, use is_base_of from boost or C++0x. If you can't use either of those, use SFINAE:
template < typename Base, typename PotentialDerived >
struct is_base
{
typedef char (&no) [1];
typedef char (&yes) [2];
static yes check(Base*);
static no check(...);
enum { value = sizeof(check(static_cast<PotentialDerived*>(0))) == sizeof(yes) };
};
The simplest solution seems to be std::is_base_of:
static_assert(std::is_base_of_v<CBaseClass, T>);
You can of course also use it in combination with if constexpr:
if constexpr (std::is_base_of_v<CBaseClass, T>) {
//
} else {
//
}
See cppreference for more details:
https://en.cppreference.com/w/cpp/types/is_base_of
Shorter is better:
template <typename Base, typename Derived>
struct is_base {
constexpr static bool check(Base*) { return true; }
constexpr static bool check(...) { return false; }
enum { value = check(static_cast<Derived*>(0)) };
};
Example 1:
struct A {};
struct B : A { };
int main(void) {
static_assert(is_base<A,B>::value, "If Error: A is not base of B");
}
Example 2:
template <bool, typename T=void>
struct Use {
static std::string info() { return "Implementation that consider that A is not base of B"; }
};
template <typename T>
struct Use<true,T> {
static std::string info() { return "Implementation that consider that A is the base of B"; }
};
int main(void) {
std::cout << Use<is_base<A,B>::value>::info(); //Implementation that consider that A is the base of B
}
I have something like:
struct A { ... };
struct B { ... };
struct C { ... };
class MyEnum {
public:
enum Value { a, b, c; }
}
template<typename T> MyEnum::Value StructToMyEnum();
template<>
MyEnum::Value StructToMyEnum<A>()
{
return MyEnum::a;
}
template<>
MyEnum::Value StructToMyEnum<B>()
{
return MyEnum::b;
}
I basically want to get a directly by calling soemthing like
StructToMyEnum<A>();
This is the best I could come up with, but when I compile I get multiple definition of 'MyEnum::Value StructToMyEnum<A>()' errors when trying to link.
Any recommendations on the best way to map types to enums as per this example?
You can map types to enums at compile time:
#include <iostream>
struct A { int n; };
struct B { double f; };
struct C { char c; };
class MyEnum
{
public:
enum Value { a, b, c };
};
template<typename T> struct StructToMyEnum {};
template<> struct StructToMyEnum<A> {enum {Value = MyEnum::a};};
template<> struct StructToMyEnum<B> {enum {Value = MyEnum::b};};
template<> struct StructToMyEnum<C> {enum {Value = MyEnum::c};};
int main (int argc, char* argv[])
{
std::cout << "A=" << StructToMyEnum<A>::Value << std::endl;
return 0;
}
The multiple definitions are because you need to either add the inline keyword or push the implementation of your specializations into a cpp file, leaving only the declarations of such in the header.
You could probably use mpl::map to write a sort-of generic version. Something like so:
struct A {};
struct B {};
struct C {};
enum Value { a,b,c };
template < typename T >
Value get_value()
{
using namespace boost::mpl;
typedef mpl::map
<
mpl::pair< A, mpl::int_<a> >
, mpl::pair< B, mpl::int_<b> >
, mpl::pair< C, mpl::int_<c> >
> type_enum_map;
typedef typename mpl::at<type_enum_map, T>::type enum_wrap_type;
return static_cast<Value>(enum_wrap_type::value);
}
Why don't you just make a static member variable of type enum and add it to your structs?
struct A
{
//Stuff
static MyEnum enumType; // Don't forget to assign a value in cpp
};
Than you can just do:
MyEnum e = StructA::enumType;
Or do you really want to use templates?