Consider
enum My_Enum {
x1, x2
};
template<class T, My_Enum X>
class A {
void f1();
void f2();
};
template<class T>
class A<T,x1> {
void g();
}
I want to use the member functions f1() and f2() of the primary template in my partially specialized template. What should I do ?
One solution would be not to do the partial specialization and then:
template<class T>
class AA<T> : public A<T,x1> {
void g();
}
but it has the drawback that when I'm instatiating A<T,X>s of all sorts by generic programming, my A<T,x1> are no longer of type AA<T> and hence I cannot apply A<T,x1>.g()
Any idea ?
How about creating a base class for class A that defines those methods?
template <class T, My_Enum X>
class A_Base {
void f1();
void f2();
};
template<class T, My_Enum X>
class A : public A_Base<T, X> {
};
template<class T>
class A<T,x1> : public A_Base<T, x1> {
void g();
};
You may create a base class:
template<class T, My_Enum X>
class BaseA {
void f1();
void f2();
};
template<class T, My_Enum X>
class A : BaseA<T,X> {
};
template<class T>
class A<T,x1> : BaseA<T,x1> {
void g();
};
Related
I'm using the Visitor pattern to implement reflection without relying on RTTI.
My problem is:
I want to implement a Visitor which can cast different classes DerivedItem1, DerivedItem2, etc. derived from the same BaseItem class, to this BaseItem class.
The base class and one of the derived classes looks like this:
class BaseItem : public AbstractItem
{
virtual ~BaseItem(){}
virtual void visit(AbstractVisitor &v)
{
v.handle(*this);
}
}
class DerivedItem1 : public BaseItem
{
virtual ~DerivedItem(){}
virtual void visit(AbstractVisitor &v)
{
v.handle(*this);
}
}
The Visitor class:
class BaseVisitor : public AbstractVisitor
{
virtual ~BaseVisitor(){}
void handle(BaseItem &item)
{
// <-- stuff to do for all classes derived from BaseItem
}
}
It is not possible to implement the BaseVisitor like this,
since DerivedItem::visit(BaseVisitor) does not cast itself to its Base class
and BaseVisitor::handle(BaseItem &v) will never get called.
I want to implement the visitor as a template class, taking a base class and all derived classes as template parameters like this:
template <typename BaseT, typename... DerivedT>
class BaseVisitor : public AbstractVisitor
{
public:
virtual ~BaseVisitor(){}
// unpacking all DerivedT should happen here
// DerivedT_X are the packed template arguments ...DerivedT
void handle(DerivedT_1 &item)
{
// <-- cast item to BaseT, do stuff, return BaseT* to caller
}
void handle(DerivedT_2 &item)
{
// <-- cast item to BaseT, do stuff, return BaseT* to caller
}
};
Is it possible somehow with C++ to let the compiler generate this member functions on its own ?
You can't unpack the parameter pack across the body of the template definition as you were describing in the question, but you can use CRTP to assemble an class that inherits a hierarchy with templatized specializations for each of the type-parameters you supply:
#include <iostream>
template<class L, class... R> struct X;
template<class L>
struct X<L> { void handle(L& i) { std::cout << i.f() << "\n"; } };
template<class L, class... R>
struct X : public X<L>, public X<R...> { using X<L>::handle; using X<R...>::handle; };
struct A1 {
int f() { return 1; }
};
struct A2 {
int f() { return 2; }
};
struct B {
int f() { return 10; }
};
struct B1 : public B {
int f() { return 11; }
};
struct B2 : public B1 {
int f() { return 12; }
};
int main() {
X<A1, A2> x1;
A1 a1; A2 a2;
x1.handle(a1);
x1.handle(a2);
X<B, B1, B2> x2;
B b; B1 b1; B2 b2;
x2.handle(b);
x2.handle(b1);
x2.handle(b2);
}
With CRTP and variadic template, you may do something like:
// The generic visitor interface
template <typename ... Ts>
class IVisitor;
template <> class IVisitor<>
{
public:
virtual ~IVisitor() = default;
};
template <typename T> class IVisitor<T>
{
public:
virtual ~IVisitor() = default;
virtual void visit(const T&) = 0;
};
template <typename T, typename...Ts>
class IVisitor<T, Ts...> : IVisitor<T>, IVisitor<Ts...>
{
public:
using IVisitor<T>::visit;
using IVisitor<Ts...>::visit;
virtual ~IVisitor() = default;
};
// Helper for the concrete visitor using CRTP
template <typename Derived, typename Base, typename...Ts>
struct CRTPVisitorImpl;
template <typename Derived, typename Base>
struct CRTPVisitorImpl<Derived, Base> : Base {};
template <typename Derived, typename Base, typename T>
struct CRTPVisitorImpl<Derived, Base, T> : virtual Base
{
using Base::visit;
void visit(const T& t) override { static_cast<Derived&>(*this).doVisit(t); }
};
template <typename Derived, typename Base, typename T, typename ... Ts>
struct CRTPVisitorImpl<Derived, Base, T, Ts...> :
CRTPVisitorImpl<Derived, Base, T>,
CRTPVisitorImpl<Derived, Base, Ts...>
{
using CRTPVisitorImpl<Derived, Base, T>::visit;
using CRTPVisitorImpl<Derived, Base, Ts...>::visit;
};
// The generic Visitor
template <typename Derived, typename Base>
struct CRTPVisitor;
template <typename Derived, typename ... Ts>
struct CRTPVisitor<Derived, IVisitor<Ts...>> :
CRTPVisitorImpl<Derived, IVisitor<Ts...>, Ts...>
{};
// Helper to write visited
template <typename Derived, typename Base, typename Visitor>
struct Visited : Base
{
void accept(Visitor& visitor) const override {
visitor.visit(static_cast<const Derived&>(*this));
}
};
And usage:
struct ShapeVisitorPrinter : CRTPVisitor<ShapeVisitorPrinter, IShapeVisitor>
{
template <typename T>
void doVisit(T&& t) const {
t.print();
}
};
each Ivisitor::visit call doVisit with CRTP, so you just have to cover each case via template/overload/base class.
Demo
How would you go about filling-in a method if a base class doesn't provide it. I'd like to reuse the base class method if it is provided.
E.g.:
#include <iostream>
struct Base0 { };
struct Base1 { void m() { std::cout<<"Base1\n"; } };
template<typename T>
struct Derived : public T {
//if T doesn't provide m, define it here, otherwise reuse the base class method
void m(){ /*? std::cout<<"Derived\n"; ?*/ }
};
int main(){
Derived<Base0> d0;
d0.m(); //should print "Derived"
Derived<Base1> d1;
d1.m(); //should print "Base1"
}
With SFINAE, you may do
template<typename T>
struct Derived : public T {
private:
template <typename U = T>
auto m_impl(int) -> decltype(std::declval<U&>().m()){ this->U::m(); }
template <typename U = T>
void m_impl(... ) { std::cout<<"Derived\n"; }
public:
void m() { m_impl(0); }
};
Demo
In order to be general, you should define the function anyway under a different signature:
template<typename T>
struct Derived : public T
{
auto m(std::false_type) { std::cout<<"Derived\n"; }
};
Then you can use the methods given in this thread in order to check whether the base class has the function m():
template <typename...>
using void_t = void;
template <typename T, template <typename> class D, typename = void>
struct detect : std::false_type {};
template <typename T, template <typename> class D>
struct detect<T, D, void_t<D<T>>> : std::true_type {};
template <typename T>
using has_m = decltype(std::declval<T>().m());
Finally, you can use that as
template<typename T>
struct Derived : public T
{
auto m(std::true_type) { return T::m(); }
auto m(std::false_type) { std::cout<<"Derived\n"; }
auto m() { return m(detect</* const */ T, has_m>{}); }
^^^^^^^^^^
//if m() is const
};
DEMO
As Aslay Berby already said this is probably not the way that you would like to go. If you want to implement something like traits or policy-based design, the following code might be what you are looking for. In fact such designs are used quite commonly and have also idiomatic value.
#include <iostream>
using namespace std;
struct StandardTraits {void foo() {cout << "standard" << endl;}};
struct Traits1 {void foo() {cout << "traits1" << endl;}};
struct Traits2 {void foo() {cout << "traits2"<< endl;}};
template<typename T = StandardTraits>
class SomeClass
{
public:
typedef T Traits;
void useTraits() {traits.foo();}
private:
Traits traits;
};
int main() {
SomeClass<> x;
SomeClass<Traits1> y;
SomeClass<Traits2> z;
x.useTraits();
y.useTraits();
z.useTraits();
return 0;
}
// output:
// standard
// traits1
// traits2
See also: https://en.wikipedia.org/wiki/Policy-based_design
I need conditional using member declaration.
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template <typename T>
struct A : public B<is_default_constructible<T>::value> {
using B<is_default_constructible<T>::value>::foo();
void foo(int) {}
};
This obviously doesn't work, because B<bool>::foo is not defined
in half the cases. How can I achieve that? To have B<>::foo()
visible in A<T> scope beside foo(int)?
Thanks for help
This is my solution. I'm sure it's won't be the best but it gets the job done.
struct A {
void foo(int) {}
};
struct A should contain methods you want defined in both cases.
template <bool> struct B;
template <> struct B<false> : A {};
template <> struct B<true> : A {
using A::foo;
void foo() {}
};
In case of B<false>, only void foo(int) is defined. In case of B<true>, both void foo(int) and void foo() are defined.
template <typename T>
struct C : public B<is_default_constructible<T>::value> {};
Now I don't have to worry about B<is_default_constructible<T>::value>::foo() not being defined in certain cases.
class D { D() = delete; };
int main()
{
C<int> c1;
c1.foo(1234);
c1.foo();
// both methods are defined for C<int>
C<D> c2;
c2.foo(1234);
// c2.foo(); // undefined method
return 0;
}
Use specialization.
enable_if can't be used for that. You need to specialize struct A too.
#include <type_traits>
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template <typename T, bool default_constructible = std::is_default_constructible<T>::value>
struct A : public B<default_constructible> {
using B<default_constructible>::foo;
void foo(int) {}
};
template<typename T>
struct A<T, false> : public B<false> {
void foo(int) {}
};
Avoiding duplicate code for foo(int)
If foo(int) will have the same functionality in both cases, you may want to derive it from another base struct:
#include <type_traits>
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template<typename T>
struct C {
void foo(int) {}
};
template <typename T, bool default_constructible = std::is_default_constructible<T>::value>
struct A : public B<default_constructible>, public C<T> {
using B<default_constructible>::foo;
using C<T>::foo;
};
template<typename T>
struct A<T, false> : public B<false>, public C<T> {
using C<T>::foo;
};
Removing that ugly bool
Finally, to remove that bool from struct A's template parameters, you may want to forward the responsibility of selecting the overloads of foo to a base class. This also has the advantage of not duplicating code for other struct A's members you may want to add.
#include <type_traits>
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template<typename T>
struct C {
void foo(int) {}
};
template <typename T, bool default_constructible = std::is_default_constructible<T>::value>
struct base_A : public B<default_constructible>, public C<T> {
using B<default_constructible>::foo;
using C<T>::foo;
};
template<typename T>
struct base_A<T, false> : public B<false>, public C<T> {
using C<T>::foo;
};
template <typename T>
struct A : public base_A<T> {
// Other members.
};
I want to specialize a constructor of a class template. This doesn't work:
template<typename T>
struct One {};
template<typename T>
struct Two {};
template<template<typename> class T, template<typename> class U>
struct Three : public T<Three<T, U>>, public U<Three<T, U>> {};
template<typename T> struct Four;
template<typename T>
struct Four
{
Four();
};
template<template<typename> class T, template<typename> class U>
Four<Three<T, U>>::Four() {}
int main(int argc, char *argv[])
{
Four<Three<One, Two> > obj;
}
but changing the class template definition to this works:
template<typename T> struct Four;
template<template<typename> class T, template<typename> class U>
struct Four<Three<T, U>>
{
Four();
};
template<template<typename> class T, template<typename> class U>
Four<Three<T, U>>::Four() {}
This seems like I'm specializing the entire class template. However I want to specialize only the constructor as in the code above - the one that doesn't work. Why can't I specialize the constructor of Four for just Three (I'm not changing the signature of the ctor of the class template)?
You can't. You must specialize the whole class. But.. you can use inheritance as a work around:
#include <iostream>
class something {};
template <typename T> class hidden_base {
public: hidden_base() {a = 1;}
protected: int a;
};
template<> class hidden_base<something> {
public: hidden_base() {a = 2;}
protected: int a;
};
template <typename T>
class your_class : public hidden_base<T> {
public:
void lots();
void of();
void other();
void member();
void functions();
void here();
void show_a() {std::cout << hidden_base<T>::a << std::endl;}
};
int main() {
your_class<long>().show_a();
your_class<int>().show_a();
your_class<something>().show_a();
}
This will print:
1
1
2
I have five classes, declared so:
template <typename T>
class A {
void fn(X);
};
template <typename T>
class B {};
class C {};
class D {};
class X {};
and I have two instances declared so:
A<B<C>> abc;
A<B<D>> abd;
How can I templatize fn so that one must call abc.fn() with an object of type C and abd.fn() with an object of type D?
You can do a partial specialization of your class like this:
template <typename T> class A;
template <typename T> class B {};
template <typename T>
class A<B<T> > {
public:
void fn(T) { }
};
class C {};
class D {};
int main(int,char**)
{
A<B<C>> abc;
A<B<D>> abd;
abc.fn(C());
abd.fn(D());
return 0;
}
If you want it to work for any template, and not just B, you can partially specialize class A like this:
template <typename T,template <typename> class U>
class A<U<T> > {
public:
void fn(T) { }
};
This is not going to be too pretty.
template <typename T>
class B {public: typedef T type;};
template <typename T>
class A {
void fn(typename T::type X);
//void fn(...){} // would prevent an error if T does not have type.
};
Basically you save the type in a typedef and then use that in A. This would error out of course if B does the T of A does not have T::type.