One template specialization for several enum values - c++

Normally if I want to have a templated (data) class by enum I would write something like this
enum class Modes : int
{
m1 = 1,
m2 = 2,
m3 = 3
};
template <Modes M>
class DataHolder
{
};
template<>
class DataHolder<Modes::m1>
{
public: int a = 4;
};
Then if I want the same specialization for the Modes::m1 as for the Modes::m2 I would write the same specialization again. Is there a way to write one specialization for several enum values? I have tried it with SFINAE, but I am not succesfull.
template <Modes M, typename = void>
class DataHolder
{
};
template<Modes M, typename = typename std::enable_if<M == Modes::m1 || M == Modes::m2>::type>
class DataHolder
{
public: int a = 4;
};
This doesn't not compile. Especially, after I would like to carry on with different specialization for Modes::m3. I've tried many similiar solution found here on SO, but nothing seems to be solving the issue.

You should put the enable_if in an explicit specialization of DataHolder which matches the default one. The specialization will be chosen if the condition in the enable_if evaluates to true.
template <Modes M, typename = void>
class DataHolder
{
};
template<Modes M>
class DataHolder<M, typename std::enable_if<M == Modes::m1 || M == Modes::m2>::type>
{
public: int a = 4;
};
int main()
{
DataHolder<Modes::m1> a; a.a;
DataHolder<Modes::m3> b; /* b.a; */
}
live example on godbolt.org

Related

enable_if on constructor

I have the following code. I want to templatize class and class constructor on enum type. However, this code does not work? How can I achieve what I want?
#include < iostream >
#include < type_traits >
enum class MyType
{
Positive,
Negative
};
template < MyType T >
struct B {
int val = 0;
template<typename U = T>
B(int n, typename std::enable_if<U==MyType::Positive>::type* = 0) : val(n) { };
template<typename U = T>
B(int n, typename std::enable_if<U==MyType::Negative>::type* = 0) : val(-n) { };
};
int main() {
B<MyType::Positive> y(10);
B<MyType::Negative> n(10);
}
Your template has a typename parameter, but you want your enum as parameter. Let's fix that:
#include <iostream>
#include <type_traits>
enum class MyType
{
Positive,
Negative
};
template <MyType T>
struct B {
int val = 0;
template<MyType U = T>
B(int n, typename std::enable_if<U==MyType::Positive>::type* = 0) : val(n) { };
template<MyType U = T>
B(int n, typename std::enable_if<U==MyType::Negative>::type* = 0) : val(-n) { };
};
int main() {
B<MyType::Positive> y(10);
B<MyType::Negative> n(10);
}
Also, you can put the SFINAE expression inside the template parameters to unclutter the constructor parameters:
template<MyType U = T, typename std::enable_if<U == MyType::Positive, int>::type = 0>
B(int n) : val(n) { };
template<MyType U = T, typename std::enable_if<U == MyType::Negative, int>::type = 0>
B(int n) : val(-n) { };
Your problem is that T is a non-type template parameter, so you cannot do typename U = T because you want U, a type template parameter, to default to T, which is a value from MyType.
The name T is very poorly chosen, which is probably why you made this mistake in the first place. Change typename U = T by MyType U = T and your code will compile.
In C++20, it would even be simpler with requires:
enum class MyType
{
Positive,
Negative
};
template <MyType E>
struct B
{
int val = 0;
B(int n) requires(E == MyType::Positive) : val(n) {}
B(int n) requires(E == MyType::Negative) : val(-n) {}
};

Define a constructor for a class whose members exist according to the template base classes

I'm working on a class to identify an image inside a texture, something like this:
using level_t = ...
using layer_t = ...
using face_t = ...
template <bool>
struct levels {};
template <>
struct levels<true> {
level_t level = level_t{0};
};
template <bool>
struct layers {};
template <>
struct layers<true> {
layer_t layer = layer_t{0};
};
template <bool>
struct faces {};
template <>
struct faces<true> {
face_t face = face_t{0};
};
template <bool HasLevels, bool HasLayers, bool HasFaces>
struct index : levels<HasLevels>, layers<HasLayers>, faces<HasFaces> {};
Where level_t, layer_t and face_t are a sort of "strong typedef" for an int (basically different types that look like an int but without the implicit conversions).
Now I can use my type like so:
using Index1 = index<true, true, false>;
void f(Index1);
Index1 v;
v.level = level_t{1};
v.layer = layer_t[1};
f(v);
But to make the life easier for my users I want to allow this code:
f({level_t{1}, layer_t{1}};
The aggregate initialization is out due the base classes, so I need to write a constructor on my own; what is the best/smartest way to write a constructor that supports all the argument combinations (but not the reorder)?
The error messages are a bit terrible if you pass the wrong types or number of arguments, so I'm not sure this is worth it, but…
One thing needed is a way to filter and randomly-access a pack of types; realistically I would use Brigand or Boost.Hana for this, but I'll stick with std::tuple<> here to keep this standard:
namespace detail {
template<template<bool> class Holder, bool B>
std::integral_constant<bool, B> holder_value_(Holder<B>);
template<typename HolderT>
constexpr decltype(detail::holder_value_(std::declval<HolderT>())) holder_value() {
return {};
}
template<typename UnfilteredT, typename FilteredT>
struct filter_holders;
template<typename UnfilteredT, typename FilteredT = std::tuple<>>
using filter_holders_t = typename filter_holders<UnfilteredT, FilteredT>::type;
template<typename... Fs>
struct filter_holders<std::tuple<>, std::tuple<Fs...>> {
using type = std::tuple<Fs...>;
};
template<typename U, typename... Us, typename... Fs>
struct filter_holders<std::tuple<U, Us...>, std::tuple<Fs...>> : filter_holders<
std::tuple<Us...>,
std::conditional_t<holder_value<U>(), std::tuple<Fs..., U>, std::tuple<Fs...>>
> { };
}
Another thing needed is a way to find what intlike-type a 'holder'-type is wrapping (e.g. that levels<true> wraps a level_t, etc.). This can be done non-intrusively, but here I'll assume an internal value_type typedef.
With those in place it's fairly straightforward – we get a pack of base types for which the template argument is true and write a constructor whose initializers are just an expansion of that pack:
namespace detail {
template<typename... HolderTs>
std::tuple<typename HolderTs::value_type...> value_types_(std::tuple<HolderTs...>);
template<typename HoldersT>
using value_types_t = decltype(detail::value_types_(std::declval<HoldersT>()));
}
template<bool HasLevels, bool HasLayers, bool HasFaces>
struct index : levels<HasLevels>, layers<HasLayers>, faces<HasFaces> {
private:
using bases_t = std::tuple<levels<HasLevels>, layers<HasLayers>, faces<HasFaces>>;
using true_bases_t = detail::filter_holders_t<bases_t>;
using arg_types_t = detail::value_types_t<true_bases_t>;
template<std::size_t... Is, typename... ArgTs>
index(std::index_sequence<Is...>, ArgTs&&... args)
: std::tuple_element_t<Is, true_bases_t>{std::forward<ArgTs>(args)}... { }
public:
index() = default;
template<
typename... ArgTs,
std::size_t S = sizeof...(ArgTs),
typename = std::enable_if_t<
S && std::is_same<std::tuple<std::decay_t<ArgTs>...>, arg_types_t>{}
>
>
index(ArgTs&&... args)
: index{std::make_index_sequence<S>{}, std::forward<ArgTs>(args)...} { }
};
Online Demo
EDIT: Updated with stricter implementation that doesn't allow convertible-but-not-same argument types, and doesn't incorrectly interfere with copy/move-construction.
Here is a demo code which allowed the code.
#include <iostream>
#include <type_traits>
struct A {
A() = default;
A(const A &) {
std::cout << "A" << std::endl;
}
};
struct B {
B() = default;
B(const B &) {
std::cout << "B" << std::endl;
}
};
struct C {
C() = default;
C(const C &) {
std::cout << "C" << std::endl;
}
};
template <class... Base>
struct Hyper : public Base... {
template <class... Args>
Hyper(Args&&... args) : Base(std::forward<Args>(args))... {}
};
template <class... Base>
auto factory(Base&&... args) {
return Hyper<std::decay_t<Base>...>(std::forward<Base>(args)...);
}
int main() {
auto obj = factory(A{}, B{}, C{});
return 0;
}
All base classes of Hyper are copy/move constructed.
Some static_assert can be added to factory to prevent it from generating any freaky class.
As the comment says, this is not a good idea. If you do it right, everything will be fine, but if you do it wrong, even a small mistake, template + multi-inheritance can be your nightmare. (You may end up with 100000 lines of compiler error message.)

Nested Template Classes

I want to be able to create a generic nested template such that I can find the total size of all classes. To start, imagine for classes A, B, C, etc... each of which have a mSize member, and GetSize() function. I do the following process:
int main()
{
using Abc = A<B<C<>>>; // Imagine it is defined similarly to this for now.
Abc abc;
std::cout << abc.GetSize() << std::endl;
// For abc.GetSize(), this will do the following:
// 1. Go into A::GetSize().
// 2. This will return A::mSize + B::GetSize()
// 3. This will go into B::GetSize()
// 4. This will return B::mSize + C::GetSize()
// 5. Etc
// Overall, we will have the total size of A+B+C as
// A::mSize + B::mSize + C::mSize.
return 0;
}
It will recursively go through each template class until the end and call GetSize(). My current attempts to do so have been using template-templates and variadic templates.
template <template<typename> class First, template<typename> class ...Args>
class A
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{1};
};
template <template<typename> class First, template<typename> class ...Args>
class B
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{2};
};
template <template<typename> class First, template<typename> class ...Args>
class C
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{3};
};
This obviously has not worked. I would really like to be able to achieve the process described in int main().
Notes:
These classes don't necessarily have to be included, or be in order. We could have A<C> or B<E<C<F<>>>>. Ideally, it can be infinitely long.
I don't want to use polymorphism, wanting it to be resolved at runtime. I could have them all inherit from the same class, create a std::vector<Parent*>, push_back each child class, and iterate through using GetSize(). It would be nice to be able to define unique types such as A<B<>>, A<B<C<>>>, etc.
Since your mSize is the same for all instance, your method should be static, and since it looks like it is a constant, it should be a constexpr.
Here is an implementation that uses a general template and then partially instantiate it with specific sizes:
template <int Size, typename T>
struct Holder {
static constexpr int GetSize() {
return Size + T::GetSize();
}
};
template <int Size>
struct Holder<Size, void> {
static constexpr int GetSize() {
return Size;
}
};
template <typename T = void>
using A = Holder<1, T>;
template <typename T = void>
using B = Holder<2, T>;
template <typename T = void>
using C = Holder<3, T>;
Then you can test:
using AB = A<B<>>;
using ABC = A<B<C<>>>;
static_assert(AB::GetSize() == 1 + 2, "Oops!");
static_assert(ABC::GetSize() == 1 + 2 + 3, "Oops!");
Of course you can make A, B, C, ... extends Holder instead of partially instantiate it if you need it.
You could do something like:
#include <iostream>
#include <type_traits>
using namespace std;
template <class T>
struct A {
static constexpr int size = 1;
using inner_type = T;
};
template <class T>
struct B {
static constexpr int size = 2;
using inner_type = T;
};
//template <class T>
struct C {
static constexpr int size = 3;
using inner_type = void;
};
template <class T, class = void>
struct TotalSizeGetter {
static constexpr int get() {
return T::size + TotalSizeGetter<typename T::inner_type>::get();
}
};
template <class T>
struct TotalSizeGetter<T, typename enable_if<is_void<typename T::inner_type>::value>::type> {
static constexpr int get() {
return T::size;
}
};
int main() {
cout << TotalSizeGetter<A<B<C>>>::get() << endl;
}
This uses c++11 constexpr and enable_if but I see this is not a limitation as you use term variadic templates in your question...

Can enum class be nested?

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.

Restrict integer template parameter

I've a code smth like this:
template<int N, typename T>
class XYZ {
public:
enum { value = N };
//...
}
Is there a way to restrict N in some way? Specifically I want to allow compilation only if N is divided by some number, let's say 6.
So it turned out to be not just a type restriction.
Preferred way is to do this without Boost.
One C++03 approach:
template<int X, int Y>
struct is_evenly_divisible
{
static bool const value = !(X % Y);
};
template<int N, typename T, bool EnableB = is_evenly_divisible<N, 6>::value>
struct XYZ
{
enum { value = N };
};
template<int N, typename T>
struct XYZ<N, T, false>; // undefined, causes linker error
For C++11, you can avoid some boilerplate and give a nicer error message:
template<int N, typename T>
struct XYZ
{
static_assert(!(N % 6), "N must be evenly divisible by 6");
enum { value = N };
};
I leave this here for the future, since I couldn't find a good example online at the time of posting.
The C++20 way with concepts:
template<int X, int Y>
concept is_evenly_divisible = X % Y == 0;
template <int N, int M> requires is_evenly_divisible<N, M>
struct XYZ
{
enum class something { value = N };
};
XYZ<12, 6> thing; // OK
//XYZ<11, 6> thing; // Error
Or even shorter:
template <int N, int M> requires (N % M == 0)
struct XYZ
{
enum class something { value = N };
};