I was trying to make a shortcut class for malloc'd unique_ptr, but I failed to extend it with default constructor. That's why I tried to make the same action on my example class, to get my hands on the error. This works perfectly:
namespace paw {
template<class T, class F>
class Cl {
public:
Cl(T* t, F f): t(t), f(f) {}
virtual ~Cl() { if (t!= 0) { f(t); } }
private:
T* t;
F f;
};
}
class ClInt : public paw::Cl<int, std::function<void(int*)>> {
public:
ClInt() : Cl(0, free) {}
ClInt(int* t) : Cl(t, free) {}
};
int main() {
ClInt clint;
}
However when I generalize ClInt class:
namespace paw {
template<class T, class F>
class Cl {
public:
Cl(T* t, F f): t(t), f(f) {}
virtual ~Cl() { if (t!= 0) { f(t); }}
private:
T* t;
F f;
};
}
template<class T>
class ClInt : public paw::Cl<T, std::function<void(T*)>> {
public:
ClInt() : Cl(0, free) {}
ClInt(T* t) : Cl(t, free) {}
};
int main() {
ClInt<int> clint;
}
i get this strange error:
error: class 'ClInt<T>' does not have any field named 'Cl'
However I cannot call superclass constructor with paw:: namespace because I get
error: expected class-name before '(' token
What is the difference and why this is not working?
Simply use the full signature for the template instances like this:
template<class T>
class ClInt : public paw::Cl<T, std::function<void(T*)>> {
public:
ClInt() : paw::Cl<T, std::function<void(T*)>>(0, free) {}
ClInt(T* t) : paw::Cl<T, std::function<void(T*)>>(t, free) {}
};
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.
Consider a class with constexpr non static member function.
template <int k> class A { A() {} };
template <> class B : public A <k> {
B() : A{} {}
constexpr int foo() const { return k+42; }
}
Is foo() really compile time with any object of B? What about constexpr members?
template <int k> class A { A() {} };
template <> class B : public A <k> {
B() : A{} {}
constexpr int foo_var = k+42;
}
Will accesses to foo_var be compile time substituted? Will B have foo_var in its object memory layout?
What about std::array<T,N>::size()??
I'm trying to build a templat-class A and call its default constructor via a special word "NONE.
consider I have:
template<class T>
class A {
public:
A():_val(0);
A(T val):_val(val);
private:
int _val;
}
and I want to be able to write
A<int> x = None;
which will call A();
I was thinking maybe I can use some sort of typedef, but I don't know how
You could provide a dummy type and a constructor that takes that type and does the equivalent of default constructing an instance. For example,
struct None_t {};
constexpr None_t None{}; // const None_t None = {}; in C++03
template<class T>
class A {
public:
A() : _val() {};
A(None_t) : A() {} // A(None_t) : _val() {} in C++03
A(T val) : _val(val) {}
private:
T _val;
};
int main()
{
A<int> x = None;
}
Note I changed _val to from int to T, since otherwise the template doesn't make much sense.
The usual way would be to create a tag class, in this case none_type and have a constexpr (or static const) model of it available.
struct none_type {};
constexpr auto none = none_type {};
template<class T>
class A {
public:
A():_val(0) {};
A(none_type) : A() {};
A(int val):_val(val) {};
private:
int _val;
};
int main()
{
A<int> a = none;
}
Given this sample code with class C deriving from A or B depending on policy
#include <iostream>
#include <type_traits>
struct A
{
A(int a) { std::cout << a << "\n"; }
};
struct B
{
B(int a) { std::cout << -a << "\n"; }
};
template<bool>
struct policy;
template<>
struct policy<true> { typedef A type; };
template<>
struct policy<false> { typedef B type; };
template<typename T>
struct C : public policy<std::is_polymorphic<T>::value>::type
{
C() : /* ????? */(5) {}
};
int main()
{
C<int> a; // should print -5
C<std::ostream> b; // should print 5
}
How do I initialize the base class of C? (or, if it's not possible, is there a workaround?)
Do it just the way you found the base class of C:
template<typename T>
struct C : public policy<std::is_polymorphic<T>::value>::type
{
C() : policy<std::is_polymorphic<T>::value>::type(5) {}
};
Of course, to make it more readable, you can also add a typedef (maybe you will need the base class multiple times within C, then it's worth it). This would look like this:
template<typename T>
struct C : public policy<std::is_polymorphic<T>::value>::type
{
typedef typename policy<std::is_polymorphic<T>::value>::type Base;
C() : Base(5) {}
};
To make it a little less ugly, you could also add another layer of indirection, e.g. a template class BaseForC that yields the correct base as BaseForC<T>::type and encapsulates what policy and is_polymorphic are doing now into one class.
Here's a lazy solution:
template <typename T,
typename Base = typename std::conditional<
std::is_polymorphic<T>::value, A, B>::type>
struct C : Base
{
C() : Base(5) {}
};
The has the cost of giving your template C a different signature, and people might abuse that.