SFINAE - recursive template - c++

I'm trying to do this:
struct A
{
typedef void NoHalf;
};
struct B : A
{
typedef A Half;
};
struct C : B
{
typedef B Half;
};
template<class T, typename = T::NoHalf> void TEST() { };
template<class T, typename = T::Half> void TEST()
{
TEST<T::Half>();
};
int main()
{
TEST<A>();
TEST<B>();
TEST<C>();
};
So the TEST<C> function should do something with class C, then recurse TEST<B>, then to TEST<A> and stop there. Unfortunately I get bunch of errors like TEST has already been defined and funny enough also TEST identifier not found. What am I doing wrong and how to fix that?

Ok, so here's a solution, quite uglier, but seems working:
struct A
{
typedef void Half;
static const int I = 0;
};
struct B : A
{
typedef A Half;
static const int I = 1;
};
struct C : B
{
typedef B Half;
static const int I = 2;
};
template<class T> std::enable_if_t<std::is_void_v<T> > TEST() { };
template<class T> std::enable_if_t<!std::is_void_v<T> > TEST()
{
printf("%i", T::I);
TEST<T::Half>();
};
int main()
{
TEST<A>();
TEST<B>();
TEST<C>();
};

Related

How to compile this both in clang and gcc?

The below code compiles in g++ but error out in clang++. How to fix this code so that it can compile in both?
class A {
private:
template<int _N> class B {
public:
static constexpr int N = _N;
};
class C {
public:
template <typename B>
B* func();
};
};
template <typename B>
B* A::C::func()
{
constexpr int N = B::N;
}
clang prior clang 11 is unbale to resolve the name B properly. The solution is use another template parameter name:
template <typename D>
D* A::C::func()
{
constexpr int N = D::N;
}
The full example requires the public access to A::C at least or a friend function.
class A {
private:
template<int N_> class B {
public:
static constexpr int N = N_;
};
class C {
public:
template <typename B>
B* func();
};
friend int main();
};
template <typename D>
D* A::C::func() {
constexpr int N = D::N;
return nullptr;
}
int main() {
A::C c;
auto *n = c.func<A::B<0>>();
}

Linked list with compile time checks in C++

I am trying to implement a linked list with compile time checks for in and out capabilities. These capabilities (or caps) shall provide information wether a valid linking can take place.
Therefore the out caps of an element are intersected with the in caps of the next element. If a valid intersection can be found, the link is established. Please see provided code for such kind of check at runtime.
While this is rather easy to accomplish at runtime, i do not know the direction for meta/template programming to handle it at compile time.
I already started reading into std::variant<>, std::visit<>, template instantiation, template specialization.
Basically, i know about meta/template programming, but only on a pre C++11 level. Please let me ask this open question, how and if this is feasible with meta/template programming.
Thanks in advance.
#include <assert.h>
#include <list>
enum class NodeType {
Type1,
Type2,
Type3
};
class Caps {
public:
NodeType type;
int minValue;
int maxValue;
};
bool intersect(const std::list<Caps>& in, const std::list<Caps>& out)
{
for (auto i : in) {
for (auto o : out) {
if (i.type == o.type) {
auto minValue = std::max(i.minValue, o.minValue);
auto maxValue = std::min(i.maxValue, o.maxValue);
if (maxValue >= minValue) {
return true;
}
}
}
}
return false;
}
class Node
{
public:
virtual bool link(Node& next) {
if (intersect(this->outCaps(), next.inCaps())) {
m_next = &next;
return true;
}
return false;
}
virtual std::list<Caps> inCaps() { return {}; }
virtual std::list<Caps> outCaps() { return {}; }
protected:
Node* m_next = nullptr;
};
class DerivedNode1 : public Node
{
public:
std::list<Caps> outCaps() override {
return { { NodeType::Type1, 1, 10 },
{ NodeType::Type2, 5, 20 } };
}
};
class DerivedNode2 : public Node
{
std::list<Caps> inCaps() override { return { { NodeType::Type1, 8, 12 } }; }
};
class DerivedNode3 : public Node
{
std::list<Caps> inCaps() override { return { { NodeType::Type2, 1, 4 } }; }
};
class DerivedNode4 : public Node
{
std::list<Caps> inCaps() override { return { { NodeType::Type3, 1, 99 } }; }
};
int main()
{
DerivedNode1 node1;
DerivedNode2 node2;
DerivedNode3 node3;
DerivedNode4 node4;
assert(node1.link(node2)); // This shall link due to matching types and ranges
assert(!node1.link(node3)); // This shall fail due to non-matching range for a specific type
assert(!node1.link(node4)); // This shall fail due to non-matching types
}
The below does what you presumably want. If you don't like the Link class, Node::link2 could be renamed to Node::link, but otherwise it needs to have a different name.
You can use either Node::link2(a, b) or a.link(b) syntax depending on what you prefer. The former doesn't need injection of the single-argument link method to derived classes, so may be preferable. The latter requires a bit more work for deep derivation to work
// Wouldn't work because `DerivedNodeY::link` and `DerivedNodeX::link` are ambiguous;
class DerivedNodeX : public DerivedNodeY, Link<DerivedNodeX>
{
public:
static constexpr std::array<Caps,1> inCaps() { ... }
// but this makes it work:
using Link<DerivedNodeX>::link;
};
Without the Link class, a derived node looks simply like:
class DerivedNode : public Node
{
public:
static constexpr std::array<Caps,1> inCaps() {
return {{ { NodeType::Type3, 1, 99 } }};
}
};
The code is C++17, it compiles with gcc and clang, but it crashes MSVC (up to 19.22) with an internal error :(. Kudos for writing a nice compiler testcase!
#include <array>
#include <type_traits>
enum class NodeType {
Type1,
Type2,
Type3
};
struct Caps {
NodeType type;
int minValue;
int maxValue;
};
class Node
{
public:
static constexpr std::array<Caps,0> inCaps() { return {}; }
static constexpr std::array<Caps,0> outCaps() { return {}; }
template <class InCaps, class OutCaps>
static constexpr bool intersect(const InCaps &in, const OutCaps &out);
template <class N1, class N2>
static std::enable_if_t<
std::is_base_of_v<Node, N1> &&
std::is_base_of_v<Node, N2> &&
intersect(N1::outCaps(), N2::inCaps()), void>
link2(N1 &prev, N2 &next) {
prev.m_next = &next;
}
protected:
Node* m_next = nullptr;
};
template <typename ThisNode>
class Link
{
public:
template <class N2> void link(N2 &next) {
Node::link2(*static_cast<ThisNode*>(this), next);
}
};
template <class InCaps, class OutCaps>
constexpr bool Node::intersect(const InCaps &in, const OutCaps &out)
{
for (auto i : in) {
for (auto o : out) {
if (i.type == o.type) {
auto minValue = std::max(i.minValue, o.minValue);
auto maxValue = std::min(i.maxValue, o.maxValue);
if (maxValue >= minValue) {
return true;
}
}
}
}
return false;
}
class DerivedNode1 : public Node, public Link<DerivedNode1>
{
public:
static constexpr std::array<Caps,2> outCaps() {
return {{ { NodeType::Type1, 1, 10 },
{ NodeType::Type2, 5, 20 } }};
}
};
class DerivedNode2 : public Node, public Link<DerivedNode2>
{
public:
static constexpr std::array<Caps,1> inCaps() {
return {{ { NodeType::Type1, 8, 12 } }};
}
};
class DerivedNode3 : public Node, public Link<DerivedNode3>
{
public:
static constexpr std::array<Caps,1> inCaps() {
return {{ { NodeType::Type2, 1, 4 } }};
}
};
class DerivedNode4 : public Node, public Link<DerivedNode4>
{
public:
static constexpr std::array<Caps,1> inCaps() {
return {{ { NodeType::Type3, 1, 99 } }};
}
};
int main()
{
DerivedNode1 node1;
DerivedNode2 node2;
DerivedNode3 node3;
DerivedNode4 node4;
Node::link2(node1, node2); // compiles
node1.link(node2);
#if 0
Node::link2(node1, node3); // fails to compile
node1.link(node3);
Node::link2(node1, node4); // fails to compile
node1.link(node3);
#endif
}
C++ doesn't have proper intersection types. But you can fake it a bit with compile-time template logic.
Say I define some capabilities as mixins:
struct cap_a {
void foo();
};
struct cap_b {
void bar();
};
struct cap_c {
void baz();
};
And a container like this that inherits from all the capabilities:
template<typename... TCaps>
struct intersectable : public TCaps... {};
I can create an intersection of two intersectable's with a mix of SFINAE and variadic templates. The resulting type only has capabilities that both inputs have.
First step of doing a cross-join is to check if a type is in a list. This is a pretty basic variadic macro. Each iteration pops off a type, checks if its the target type, and or's it with the next iteration.
template<typename TCap, typename... TCaps>
struct has_capability_impl;
template<typename TCap, typename TCapFirst, typename... TCaps>
struct has_capability_impl<TCap, TCapFirst, TCaps...> {
static constexpr bool value = std::is_convertible<TCap, TCapFirst>::value || has_capability_impl<TCap, TCaps...>::value;
};
template<typename TCap>
struct has_capability_impl<TCap> {
static constexpr bool value = false;
};
template<typename TCap, typename... TCaps>
constexpr bool has_capability = has_capability_impl<TCap, TCaps...>::value;
You can do this with fold expressions in C++17, but this works in older versions.
Next is the intersection. This a template with 3 types: An empty result itersectable, the left hand side, and branches with enable_if. If the type is present on the right intersectable, move the type over to the result in the inherited base type. OTherwise, don't.
For each iteration, pop a type off a
template<typename TLRhs, typename TLhs, typename TRhs, typename = void>
struct intersect_impl;
template<typename... TLRCaps, typename TFirst, typename... TLCaps, typename... TRCaps>
struct intersect_impl<intersectable<TLRCaps...>, intersectable<TFirst, TLCaps...>, intersectable<TRCaps...>, std::enable_if_t<has_capability<TFirst, TRCaps...>>> : intersect_impl<intersectable<TLRCaps..., TFirst>, intersectable<TLCaps...>, intersectable<TRCaps...>> { };
template<typename... TLRCaps, typename TFirst, typename... TLCaps, typename... TRCaps>
struct intersect_impl<intersectable<TLRCaps...>, intersectable<TFirst, TLCaps...>, intersectable<TRCaps...>, std::enable_if_t<!has_capability<TFirst, TRCaps...>>> : intersect_impl<intersectable<TLRCaps...>, intersectable<TLCaps...>, intersectable<TRCaps...>> { };
By the time there are no types left on the left hand side, the result only has capabilities present from both sides:
template<typename... TLRCaps, typename... TRCaps>
struct intersect_impl<intersectable<TLRCaps...>, intersectable<>, intersectable<TRCaps...>> {
using type = intersectable<TLRCaps...>;
};
template<typename TLhs, typename TRhs>
using intersection = typename intersect_impl<intersectable<>, TLhs, TRhs, void>::type;
Package that in a trivial function to combine instances:
template<typename TLhs, typename TRhs>
intersection<TLhs, TRhs> intersect(TLhs lhs, TRhs rhs) {
return intersection<TLhs, TRhs>{}; // runtime link logic goes here
}
...and the result is type-safe capability intersections:
int main() {
intersectable<cap_a, cap_c> ac;
ac.foo();
ac.baz();
intersectable<cap_a, cap_b> ab;
ab.foo();
ab.bar();
auto a = intersect(ac, ab);
a.foo();
a.bar(); // error
a.baz(); // error
}
Demo: https://godbolt.org/z/-kd2Qj
Again, this doesn't actually do anything, it just intersects the types. But you can use something like this to make your linked list logic type-safe.
Anyway, to add range checking, it's just a matter of working in compile-time properties for range into the definition of intersectable
#include <cstdint>
#include <functional>
#include <type_traits>
#include <unordered_set>
struct cap_a {
void foo();
};
struct cap_b {
void bar();
};
struct cap_c {
void baz();
};
template<int Min, int Max, typename... TCaps>
struct intersectable : public TCaps... {
};
template<typename TCap, typename... TCaps>
struct has_capability_impl;
template<typename TCap, typename TCapFirst, typename... TCaps>
struct has_capability_impl<TCap, TCapFirst, TCaps...> {
static constexpr bool value = std::is_convertible<TCap, TCapFirst>::value || has_capability_impl<TCap, TCaps...>::value;
};
template<typename TCap>
struct has_capability_impl<TCap> {
static constexpr bool value = false;
};
template<typename TCap, typename... TCaps>
constexpr bool has_capability = has_capability_impl<TCap, TCaps...>::value;
template<typename TLRhs, typename TLhs, typename TRhs, typename = void>
struct intersect_impl;
template<int LRMin, int LRMax, int LMin, int LMax, int RMin, int RMax, typename... TLRCaps, typename TFirst, typename... TLCaps, typename... TRCaps>
struct intersect_impl<
intersectable<LRMin, LRMax, TLRCaps...>,
intersectable<LMin, LMax, TFirst, TLCaps...>,
intersectable<RMin, RMax, TRCaps...>,
std::enable_if_t<(has_capability<TFirst, TRCaps...>)>>
: intersect_impl<
intersectable<LRMin, LRMax, TLRCaps..., TFirst>,
intersectable<LMin, LMax, TLCaps...>,
intersectable<RMin, RMax, TRCaps...>> { };
template<int LRMin, int LRMax, int LMin, int LMax, int RMin, int RMax, typename... TLRCaps, typename TFirst, typename... TLCaps, typename... TRCaps>
struct intersect_impl<
intersectable<LRMin, LRMax, TLRCaps...>,
intersectable<LMin, LMax, TFirst, TLCaps...>,
intersectable<RMin, RMax, TRCaps...>,
std::enable_if_t<(!has_capability<TFirst, TRCaps...>)>>
: intersect_impl<
intersectable<LRMin, LRMax, TLRCaps...>,
intersectable<LMin, LMax, TLCaps...>,
intersectable<RMin, RMax, TRCaps...>> { };
template<int LMin, int LMax, int RMin, int RMax, typename TResult, typename... TRCaps>
struct intersect_impl<TResult, intersectable<LMin, LMax>, intersectable<RMin, RMax, TRCaps...>> {
using type = TResult;
};
template <typename T>
struct props;
template<int Min, int Max, typename... Caps>
struct props<intersectable<Min, Max, Caps...>> {
static constexpr int min = Min;
static constexpr int max = Max;
};
template<typename TLhs, typename TRhs>
using intersection = typename intersect_impl<
intersectable<(std::max(props<TLhs>::min, props<TRhs>::min)), (std::min(props<TLhs>::max, props<TRhs>::max))>,
TLhs,
TRhs>::type;
template<typename TLhs, typename TRhs>
intersection<TLhs, TRhs> intersect(TLhs lhs, TRhs rhs) {
static_assert((props<TLhs>::max >= props<TRhs>::min && props<TLhs>::min <= props<TRhs>::max) ||
(props<TRhs>::max >= props<TLhs>::min && props<TRhs>::min <= props<TLhs>::max), "out of range");
return intersection<TLhs, TRhs>{}; // runtime intersection logic?
}
int main() {
intersectable<1, 5, cap_a, cap_c> ac;
ac.foo();
ac.baz();
intersectable<3, 8, cap_a, cap_b> ab;
ab.foo();
ab.bar();
auto a = intersect(ac, ab); // result is a intersectable<3, 5, cap_a>
a.foo();
a.bar(); // error
a.baz(); // error
intersectable<10, 15, cap_a, cap_b> ab_out_of_range;
auto a0 = intersect(ac, ab_out_of_range);
}
demo: https://godbolt.org/z/zz9-Vg

multiple virtual inheritance and variadic template

In my project I played with the following design :
enum {
A = 1, B = 2, C = 4
};
struct Foo { int foo; };
template <int> struct Bar;
template <> struct Bar<A> : public virtual Foo { int a; };
template <> struct Bar<B> : public virtual Foo { int b; };
template <> struct Bar<C> : public virtual Foo { int c; };
Now I can do something fun like :
template <> struct Bar<A|B> : public A, public B {};
template <> struct Bar<A|C> : public A, public C {};
template <> struct Bar<B|C> : public B, public C {};
template <> struct Bar<A|B|C> : public A, public B, public C {};
So that I can write :
Bar<A|C> bar;
bar.foo = 2;
bar.a = 1;
bar.c = 2;
Now I would like the generation of the combination classes Bar<X|Y|Z|..> to be automatically done when the user creates such an instance.
Is this possible using some template magic ?
Something along the lines of :
template <int N, class ...Classes> struct Bar<N> : public Classes... {};
template <int N> struct Bar<N> : public Bar<N, generate_classes<N> > {};
where generate_classes would be able to generate the list of classes Bar<N> should inherit from.
No need in fancy schmancy SFINAE, parameter packs or any such dark wizardry.
enum {
A = 1, B = 2, C = 4
};
struct Foo { int foo; };
template <unsigned int> struct Bar; // unsigned because bit fiddling
template <> struct Bar<A> : public virtual Foo { int a; };
template <> struct Bar<B> : public virtual Foo { int b; };
template <> struct Bar<C> : public virtual Foo { int c; };
template <unsigned int i> struct Bar :
public Bar<i & ~(i-1)>, // only least significant set bit
public Bar<i & (i-1)> // all other set bits
{ };
// checking
int main ()
{
Bar<A|B|C> abc;
abc.a = 0; // ok
abc.b = 0; // ok
abc.c = 0; // ok
Bar<A|B> ab;
ab.a = 0; // ok
ab.b = 0; // ok
ab.c = 0; // error
Bar<A|C> ac;
ac.a = 0; // ok
ac.b = 0; // error
ac.c = 0; // ok
Bar<9> x; // error
}
Instead of thinking about somehow generating a list of classes to be inherited you can think of it as choosing them. This one should be inherited, this one shouldn't. This can be achieved by static dispatching through template parameter. So we get a template that based on a bool parameter gives either T or an empty class. It is likely to be optimized (it may even be guaranteed in this case, but I'm not sure what exact requirements given by the standard are) by empty base optimization so there is no memory overhead.
#include <iostream>
enum {
A = 1, B = 2, C = 4
};
template <class T, bool Enable>
struct or_empty;
template <class T>
struct or_empty<T, false>
{
struct empty {};
using type = empty;
};
template <class T>
struct or_empty<T, true>
{
using type = T;
};
template <class T, bool Enable>
using or_empty_t = typename or_empty<T, Enable>::type;
struct Foo { int foo; };
template <int I> struct Bar :
public or_empty_t<Bar<A>, I&A>,
public or_empty_t<Bar<B>, I&B>,
public or_empty_t<Bar<C>, I&C> {};
template <> struct Bar<A> : public virtual Foo { int a; };
template <> struct Bar<B> : public virtual Foo { int b; };
template <> struct Bar<C> : public virtual Foo { int c; };
int main()
{
Bar<A|C> bar;
bar.foo = 2;
bar.a = 1;
// bar.b = 2; error
bar.c = 2;
std::cout << bar.foo << ' ' << bar.a << ' ' << bar.c << '\n';
std::cout << sizeof(Bar<A>) << ' ' << sizeof(Bar<A|B>) << ' ' << sizeof(Bar<A|B|C>) << '\n';
}
Demo: http://coliru.stacked-crooked.com/a/f170fbd873739c38
Some machinery to do compile-time unpacking of flags:
enum flag_e { None = 0, A = 1, B = 1<<1, C = 1<<2 };
template<flag_e...>
struct flags {using type=flags; constexpr flags(){}};
template<flag_e>
struct flag{using type=flag; constexpr flag(){}};
constexpr flags<A,B,C> all_flags{};
template<flag_e...lhs, flag_e...rhs>
constexpr flags<lhs...,rhs...> operator+(flags<lhs...>, flags<rhs...>)
{ return {}; }
template<flag_e lhs, flag_e...rhs>
inline constexpr flags<lhs, rhs...> operator+(flag<lhs>, flags<rhs...>)
{ return {}; }
template<flag_e...lhs, flag_e rhs>
inline constexpr flags<lhs..., rhs> operator+(flags<lhs...>, flag<rhs>)
{ return {}; }
template<flag_e...fs>
inline constexpr flags<fs...> operator+(flag<None>, flags<fs...>)
{ return {}; }
template<flag_e...fs>
inline constexpr flags<fs...> operator+(flags<fs...>, flag<None>)
{ return {}; }
template<flag_e f, flag_e...fs>
inline constexpr auto unpack( flag<f>, flags<fs...> x, flags<> )
-> flags<fs...>
{ return {}; }
template<flag_e f, flag_e...fs, flag_e c0, flag_e...checks>
inline constexpr auto unpack( flag<f> fin, flags<fs...> x, flags<c0, checks...> )
-> decltype( unpack( fin, x+flag<flag_e(f&c0)>{}, flags<checks...>{} ) )
{ return {}; }
template<flag_e f>
inline constexpr auto unpack( flag<f> fin )
-> decltype( unpack( flag<f>{}, flags<>{}, all_flags ) )
{ return {}; }
Then we use it:
template <int> struct Bar;
template <class flags> struct BarImpl;
template <flag_e...fs> struct BarImpl<flags<fs...>>:
Bar<fs>...
{};
template <int flags> struct Bar:
BarImpl<decltype(unpack(flag<flag_e(flags)>{}))>
{};
struct Foo { int foo; };
template <> struct Bar<A> : public virtual Foo { int a; };
template <> struct Bar<B> : public virtual Foo { int b; };
template <> struct Bar<C> : public virtual Foo { int c; };
Live example.
The code that lets you have bundles of flags and individual flags can be made more generic at the cost of mentioning the flag_e type more often.
I made it overly slick, with the ability to say flags<A>+flags<B> and get flags<A,B>, because I like that notation.
I then wrote unpack, which takes flag<A|B> and produces flags<A,B>.
In C++14 and 17 things get slicker, which folds and return type deduction and the like.

Get size of polymorphic object

I want to be able to get the size of polymorphic object. At the moment I got this:
struct Base {
virtual std::size_t size() const {
return sizeof(*this);
}
};
struct Derived : Base {
virtual std::size_t size() const {
return sizeof(*this);
}
};
Which is literally copy & paste. I want to do better. Suppose I really hate macros and CRTP seems like the only sensible approach. Let us give it a try:
struct SizedBase {
virtual std::size_t size() const = 0;
};
template <typename Type>
struct Sized : virtual SizedBase {
std::size_t size() const override {
return sizeof(Type);
}
};
struct Base : Sized<Base> {};
struct Derived : Base, Sized<Derived> {};
This looks much better, but sadly is ill-formed: Derived contains two final overriders for size() from Base and from Sized<Derived>. We can solve this by inheriting through Sized:
struct SizedBase {
virtual std::size_t size() const = 0;
};
template <typename Type, typename... SizedBases>
struct Sized : virtual SizedBase, SizedBases... {
std::size_t size() const override {
return sizeof(Type);
}
};
struct Base : Sized<Base> {};
struct Derived : Sized<Derived, Base> {};
This works as intended, however gets somewhat confusing in the event of multiple inheritance and prohibits altering accessibility/virtualness of bases.
So, is there a better way?
Not that anyone should really use this, but...
template <typename>
struct None1 {};
template <typename>
struct None2 {};
template <typename T>
struct PrivateBase { using Tpriv = T; using Tprot = None1<T>; using Tpub = None2<T>; };
template <typename T>
struct ProtectedBase { using Tpriv = None1<T>; using Tprot = T; using Tpub = None2<T>; };
template <typename T>
struct PublicBase { using Tpriv = None1<T>; using Tprot = None2<T>; using Tpub = T; };
template <typename K>
struct TriBase : private K::Tpriv, protected K::Tprot, public K::Tpub {};
template <typename T, typename ... Bases>
struct Sized : private Bases::Tpriv..., protected Bases::Tprot..., public Bases::Tpub...
{
virtual size_t size() { return sizeof(T); }
};
struct Foo : Sized<Foo> {};
struct X{};
struct Y{};
struct Bar : Sized<Bar, PrivateBase<X>, ProtectedBase<Y>, PublicBase<Foo>> {};
int main ()
{
Bar b;
Foo* f = &b;
X* x = &b; // error : private base
Y* y = &b; // error : protected base
}
Virtual inheritance is left as an exercise to the reader.
The order of base classes is not preserved, but you should not depend on it anyway.
Something that is a little bit more production-friendly can be implemented like this (this is a rough sketch):
#include <cstdlib>
#include <typeinfo>
#include <unordered_map>
#include <memory>
#include <iostream>
struct myinfo
{
size_t size;
// any other stuff
};
using TypeInfoRef = std::reference_wrapper<const std::type_info>;
struct Hasher
{
std::size_t operator()(TypeInfoRef code) const
{
return code.get().hash_code();
}
};
struct EqualTo
{
bool operator()(TypeInfoRef lhs, TypeInfoRef rhs) const
{
return lhs.get() == rhs.get();
}
};
static std::unordered_map<TypeInfoRef, myinfo, Hasher, EqualTo> typemap;
template <typename K>
struct typemap_initializer
{
typemap_initializer()
{
typemap[typeid(K)] = myinfo{sizeof(K)};
}
};
struct Base
{
virtual ~Base() {}
size_t size() { return typemap[typeid(*this)].size; }
template<typename K, typename... Arg>
friend K* alloc(Arg...);
private:
void* operator new(size_t sz) { return ::operator new(sz); }
};
template<typename K, typename... Arg>
K* alloc(Arg... arg)
{
static typemap_initializer<K> ti;
return new K(arg...);
}
struct Foo : Base {int a;};
struct Bar : Foo {int b; int c;};
int main ()
{
Foo* f = alloc<Foo>();
Bar* g = alloc<Bar>();
std::cout << f->size() << std::endl;
std::cout << g->size() << std::endl;
}
Of course one gives up the familiar Foo* foo = new Foo syntax, but in the era of ubiquitous std::make_shared<> this is not a big problem.

C++ Template for mapping struct type to enum?

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?