How to pass other template parameter when template class uses parameter pack? - c++

I would like to create template class that implements print() method for each type passed as template parameters.
Something like that:
class Interface
{
public:
virtual ~Interface() = default;
virtual void print(int) = 0;
virtual void print(double) = 0;
};
X x<int, double, Interface>;
class X has public method void print() and it works.
The whole code below:
#include <iostream>
#include <type_traits>
struct Printer
{
void print(int i) {std::cout << i << std::endl; }
void print(double d) {std::cout << d << std::endl; }
};
class Interface
{
public:
virtual ~Interface() = default;
virtual void print(int) = 0;
virtual void print(double) = 0;
};
template <typename... Args>
class X;
template <typename Interface>
class X<Interface> : public Interface
{
static_assert(std::is_abstract<Interface>::value, "Last argument should be an interface");
public:
X(Printer printer) {}
using Interface::print;
};
template <typename Arg, typename... Args>
class X<Arg, Args...> : public X<Args...>
{
using Parent = X<Args...>;
public:
using Parent::print;
X(Printer printer_): Parent(printer), printer{printer_} {}
void print(Arg arg) override { printer.print(arg); }
private:
Printer printer;
};
int main()
{
Printer printer;
X<double, int, Interface> x(printer);
x.print(5);
}
As you see class X uses Printer class but the problem is that I would like to have Printer as a template parameter...
Is it possible? How to do that?

As you see class X uses Printer class but the problem is that I would like to have Printer as a template parameter...
Is it possible? How to do that?
Sorry but... I don't see the problem (with a great simplification suggested by Story Teller: place a single Printer object in the ground case case)
template <typename...>
class X;
template <typename Printer, typename Interface>
class X<Printer, Interface> : public Interface
{
static_assert(std::is_abstract<Interface>::value,
"Last argument should be an interface");
public:
X (Printer p0) : printer{p0}
{ }
using Interface::print; // why?
protected:
Printer printer;
};
template <typename Printer, typename Arg, typename... Args>
class X<Printer, Arg, Args...> : public X<Printer, Args...>
{
using Parent = X<Printer, Args...>;
public:
using Parent::print;
using Parent::printer;
X(Printer printer_): Parent{printer_} {}
void print(Arg arg) override { printer.print(arg); }
};
// ....
X<Printer, double, int, Interface> x(printer);
Off topic: attention: you're using printer uninitialized
X(Printer printer_): Parent(printer), printer{printer_} {}
I suppose you should write Parent(printer_)

Assuming that the polymorphic interface is required.
polymorphism reduces the value of variadic template expansion
preserving the deferral of action to an encapsulated printer
A possible solution:
#include <iostream>
#include <type_traits>
// Abstract interface
class PrintInterface
{
public:
virtual ~PrintInterface() = default;
virtual void print(int) = 0;
virtual void print(double) = 0;
};
// An implmentation of PrintInterface that defers to PrinterType
template<class PrinterType>
class ImplementPrintInterface : public PrintInterface
{
public:
ImplementPrintInterface(PrinterType printer)
: printer_(std::move(printer))
{}
virtual void print(int x) override
{
printer_.print(x);
}
virtual void print(double x) override
{
printer_.print(x);
}
private:
PrinterType printer_;
};
// An implementation of a thing that prints ints and doubles.
// This happens to match PrintInterface but there is no inheritance
struct Printer
{
void print(int i) {std::cout << i << std::endl; }
void print(double d) {std::cout << d << std::endl; }
};
// X *is a* PrinterInterface that *uses a* PrinterType
template <typename PrinterType>
class X : public ImplementPrintInterface<PrinterType>
{
public:
X(PrinterType printer = PrinterType())
: ImplementPrintInterface<PrinterType>(std::move(printer))
{}
};
int main()
{
Printer printer;
X<Printer> x(printer);
x.print(5);
}

Related

Implementing virtual functions' overriding mechanism with templates

I recently had a thought of implementing virtual functions without virtual tables or storing a pointer with CRTP (though using static_cast<CRTP&>(*this) instead.
The initial set up is rather cumbersome compared to conventional virtual functions.
So the code is:
namespace detail
{
template<typename T, typename = void>
struct virtual_set_up
{
void operator()(T &) {}
};
template<typename T>
struct virtual_set_up<T, std::void_t<decltype(std::declval<T>().set_up())>>
{
void operator()(T &t) { t.set_up(); }
};
}
template<typename CRTP>
class base
{
public:
base() {}
void set_up() { detail::virtual_set_up<CRTP>()(static_cast<CRTP &>(*this)); }
protected:
~base() = default;
};
class settable : public base<settable>
{
public:
void set_up() { std::cout << "settable: set_up overridden" << std::endl; }
};
class dummy : public base<dummy>
{
public:
};
int main(int, char **)
{
settable s;
dummy d;
base<settable>& baseS = s;
base<dummy>& baseD = d;
baseS.set_up();
baseD.set_up();
return 0;
}
However there is a problem: virtual_set_up<dummy> resolves to the specialization of T with declared T::set_up causing a SEGFAULT upon execution. It happens because dummy is publicly inheriting from base, which does have a set_up method.
Given that the previous problem is solvable, does this add any efficiency over having a conventional virtual function?
To solve your infinite recursion, you might still compare that "&dummy::setup != &base<dummy>::setup":
namespace detail
{
template <typename B, typename T, typename = void>
struct virtual_set_up
{
void operator()(T&) {}
};
template <typename B, typename T>
struct virtual_set_up<B, T,
std::enable_if_t<!std::is_same_v<decltype(&B::set_up),
decltype(&T::set_up)>>>
{
void operator()(T& t) { t.set_up(); }
};
}
template <typename CRTP>
class base
{
public:
base() {}
void set_up() { detail::virtual_set_up<base, CRTP>()(static_cast<CRTP &>(*this)); }
protected:
~base() = default;
};
Demo
But simpler would be to rename/split the one in base<CRTP>
template <typename CRTP>
class base
{
public:
base() {}
void set_up() { static_cast<CRTP &>(*this).set_up_v(); }
void set_up_v() { std::cout << "base\n"; }
protected:
~base() = default;
};
class settable : public base<settable>
{
public:
void set_up_v() { std::cout << "settable: set_up overridden" << std::endl; }
};
Demo
Does this add any efficiency over having a conventional virtual function?
All code there are resolve at compilation, there are no dynamic dispatch, so no overhead of virtual dispatch...
But you have nothing which is polymorphic neither here: base<dummy> and base<settable> are unrelated classes (you cannot have std::vector<base> to store then together). So comparison is unfair.
For case where all types are known at compile-time, compilers might use devirtualization optimization and remove the overhead of virtual call too.

How to implement a fully generic Visitor for a hierarchy of classes in C++1x?

I'd like to implement a fully generic Visitor pattern using >= C++14 using template metaprogramming. I've already found a nice way to generalize the Visitor itself, but I'm having trouble defining the Visitables. The code below works, but I'd like the commented out code in main to work as well; in particular, I want to be able to have a collection of Visitables and apply a Visitor to each element.
Is what I'm trying to do even possible in C++?
Things I've tried:
class X : public Visitable<X>
This solves the problem of not having a suitable accept method in
X, but results in ambiguities X/A and X/B which the compiler
cannot resolve.
empty accept method in X without inheriting; works, but the
specialized accept methods in A and B are never called.
replace template class Visitor with regular class with function
template visit for arbitrary types; does not really change the
semantics, but is less readable IMHO
#include <iostream>
#include <vector>
template <typename I>
class Visitable {
public:
template <typename Visitor>
void accept(Visitor&& v) const {
v.visit(static_cast<const I&>(*this));
}
};
template <typename T, typename... Ts>
class Visitor : public Visitor<Ts...> {
public:
virtual void visit(const T& t);
};
template<typename T>
class Visitor<T> {
public:
virtual void visit(const T& t);
};
struct X {
// template <typename V> void accept(V&& v) const {};
};
struct A : public X, public Visitable<A> {};
struct B : public X, public Visitable<B> {};
class MyVisitor : public Visitor<A, B> {
public:
void visit(const A& a) override { std::cout << "Visiting A" << std::endl; }
void visit(const B& b) override { std::cout << "Visiting B" << std::endl; }
};
int main() {
MyVisitor v {};
// std::vector<X> elems { A(), B() };
// for (const auto& x : elems) {
// x.accept(v);
// }
A().accept(v);
B().accept(v);
}
There are a few issues with your current solution:
You don't have a polymorphic type that can represent any visitable type. This means that you don't have a way to properly store all your A and B values in a collection such that you can visit every element in the collection. X doesn't accomplish this because there is no way to require that a subclass of X also subclasses an instantiation of the Visitable class template.
You have no way of handling a mismatch of visitor/visitable types; you cannot guarantee that all values in your collection are visitable by some visitor type, without simply making the collection a vector<A> or vector<B>, in which case you lose the ability to store values of different visitable types in the same collection. You either need a way to handle at runtime the scenario of a visitor/visitable mismatch, or you need a much more complex template structure.
You cannot store polymorphic values directly in a collection. This is because vector stores its elements consecutively in memory, and therefore must assume a certain constant size for each element; by their nature polymorphic values have an unknown size. The solution is to use a collection of (smart) pointers to refer to polymorphic values elsewhere on the heap.
Here's a working adaptation of your original code:
#include <iostream>
#include <vector>
#include <memory>
template<typename T>
class Visitor;
class VisitorBase {
public:
virtual ~VisitorBase() {}
};
class VisitableBase {
public:
virtual void accept(VisitorBase& v) const = 0;
virtual ~VisitableBase() {}
};
template <typename I>
class Visitable : public VisitableBase {
public:
virtual void accept(VisitorBase& v) const {
auto visitor = dynamic_cast<Visitor<I> *>(&v);
if (visitor == nullptr) {
// TODO: handle invalid visitor type here
} else {
visitor->visit(dynamic_cast<const I &>(*this));
}
}
};
template<typename T>
class Visitor : public virtual VisitorBase {
public:
virtual void visit(const T& t) = 0;
};
struct A : public Visitable<A> {};
struct B : public Visitable<B> {};
class MyVisitor : public Visitor<A>, public Visitor<B> {
public:
void visit(const A& a) override { std::cout << "Visiting A" << std::endl; }
void visit(const B& b) override { std::cout << "Visiting B" << std::endl; }
};
int main() {
MyVisitor v {};
std::vector<std::shared_ptr<VisitableBase>> elems {
std::dynamic_pointer_cast<VisitableBase>(std::make_shared<A>()),
std::dynamic_pointer_cast<VisitableBase>(std::make_shared<B>())
};
for (const auto& x : elems) {
x->accept(v);
}
A().accept(v);
B().accept(v);
}
struct empty_t{};
template <class I, class B=empty_t>
class Visitable:public B {
public:
// ...
struct X : Visitable<X>{
};
struct A : Visitable<A,X> {};
struct B : Visitable<B,X> {};
Note however that dispatch here is static. And your vector contains Xs not As or Bs.
You probably want
template <class Visitor>
struct IVisitable {
virtual void accept(Visitor const& v) const = 0;
protected:
~IVisitable(){}
};
template <class I, class Visitor, class B=IVisitable<Visitor>>
struct Visitable {
virtual void accept(Visitor const& v) const override {
v.visit(static_cast<const I&>(*this));
}
};
which gets closer.
struct A; struct B; struct X;
struct X:Visitable<X, Visitor<A,B,X>> {
};
struct A :Visitable<A, Visitor<A,B,X>, X> {};
struct B :Visitable<B, Visitor<A,B,X>, X> {};
this still doesn't do what you want, because you have a vector of values. And polymorphic values require more work.
Make it a vector of unique ptrs to X, and add virtual ~X(){} and some * and make_uniques and this will do what you want.

Simplifying API of classes extending each other by CRTP

I want to write class that extends multiple classes by (CRTP).
I can only get Extension<Base<Extension>> my_object; to work.
The api that I want is: Extension<Base> my_object;
How to make this api work?
Thanks.
Test (code is also at godbolt.org):
#include <iostream>
template <template<typename...> class Extension>
class Base1 : public Extension<Base1<Extension>> {
public:
static void beep() { std::cout << "Base1 "; }
};
template <class Plugin>
class Extension1 {
public:
Extension1() : plugin_(static_cast<Plugin*>(this)) {}
void beep() {
plugin_->beep();
std::cout << "Extension1\n";
}
private:
Plugin* plugin_;
};
template <template<typename...> class Plugin>
class Extension2 {
public:
Extension2() : plugin_(static_cast<Plugin<Extension2>*>(this)) {}
void beep() {
plugin_->beep();
std::cout << "Extension2\n";
}
private:
Plugin<Extension2>* plugin_;
};
int main() {
// This works.
Extension1<Base1<Extension1>>b;
b.beep();
// This doesn't work.
Extension2<Base1> c;
c.beep();
return 0;
}
One problem is that the template parameter to Extension2 does not match the signature that Base1 has. Another is that Extension2 does not match the parameter type expected by Base1.
If you change the definition of Extension2 to propertly accept Base1, it itself is still not a candidate to be passed to Base1. You can workaround that with an inner template class that does match what Base1 expects. This inner class would look a lot like Extension1.
template <template<template<typename...> class> class Plugin>
class Extension2 {
template <class P>
struct Inner {
Inner () : plugin_(static_cast<P *>(this)) {}
void beep() { plugin_->beep(); }
private:
P* plugin_;
};
public:
Extension2() {}
void beep() {
plugin_.beep();
std::cout << "Extension2\n";
}
private:
Inner<Plugin<Inner>> plugin_;
};

How to create flexible templates C++

I am trying to create abstract class which is a template for another classes. Is it possible to create "flexible" template?
Several classes will inherit from this one, all of them will have the functions with the same name, but with different arguments. The abstract class is "Interface" of inheritance classes - I will use pointer of this one to manage another.
For example we have two classes: A and B.
find method of A class needs only type1 type, but the same method of B class needs type1 and type2 types.
This is how I am creating classes that inherit from template:
class A : public Repository<int> {
public void find(int) override; };
class B : public Repository<int, float> {
public void find(int a, float b) override; };
Its all about the part after public keyword. I don't want to type <int, float> to all classes.
I there any way to overload(?) the template<typename type1, typename type2> and the function?
The code of the abstract class.
#ifndef REPOSITORY_HPP
#define REPOSITORY_HPP
#include <string>
//template<typename type1>
template<typename type1, typename type2>
class Repository
{
protected:
typeSTRING name;
public:
virtual void find(type1) = 0;
//virtual void find(type1, type2) = 0;
};
#endif
You would need variadic template in base class, i.e
#include <iostream>
template <typename ... Args>
class Interface
{
public:
virtual void find(Args... args) = 0;
};
class Impl1 : public Interface<int>
{
public:
void find(int value) override
{
std::cout << "found" << value << std::endl;
}
};
class Impl2 : public Interface<int, float>
{
public:
void find(int value, float other_value) override
{
std::cout << "found" << value << " " << other_value << std::endl;
}
};
int main()
{
Impl1 impl1 {};
impl1.find(5);
Impl2 impl2 {};
impl2.find(5, 10.2);
}
To complement the below comment from #KKMKK, this is how you can get an specific type from Args... (from: get the Nth type of variadic template templates?):
template <typename ... Args>
class Interface
{
public:
using FirstType = typename std::tuple_element<0, std::tuple<Args...> >::type;
virtual void add(FirstType) = 0;
virtual void find(Args... args) = 0;
};
class Impl2 : public Interface<int, float>
{
public:
void add(int value) override
{
std::cout << "found" << value << std::endl;
}
void find(int value, float other_value) override
{
std::cout << "found" << value << " " << other_value << std::endl;
}
};
int main()
{
Impl2 impl2 {};
impl2.add(5);
impl2.find(5, 10.2);
}

Using the Visitor Pattern with template derived classes

I try to implement the Visitor pattern with templated derived classes
I work with gcc 4.5
here is the VisitorTemplate.hpp, I specialized Derived in the class Visitor, but I'd like to be able to handle any type:
edit : thanks to the suggestions of interjay, the code compiles and runs without errors now
#ifndef VISITORTEMPLATE_HPP_
#define VISITORTEMPLATE_HPP_
#include <iostream>
#include <string>
using namespace std;
template<class T> Derived;
class Visitor
{
public:
virtual void visit(Derived<string> *e) = 0;
};
class Base
{
public:
virtual void accept(class Visitor *v) = 0;
};
template<class T>
Derived: public Base
{
public:
virtual void accept(Visitor *v)
{
v->visit(this);
}
string display(T arg)
{
string s = "This is : " + to_string(arg);
return s;
}
};
class UpVisitor: public Visitor
{
virtual void visit(Derived<string> *e)
{
cout << "do Up on " + e->display("test") << '\n';
}
};
class DownVisitor: public Visitor
{
virtual void visit(Derived<string> *e)
{
cout << "do Down on " + e->display("test") << '\n';
}
};
#endif /* VISITORTEMPLATE_HPP_ */
main.cpp
Base* base = new Derived<string>();
Visitor* up = new UpVisitor();
Visitor* down = new DownVisitor();
base->accept(up);
base->accept(down);
Now my goal is to use Derived in visit without specializing; unfortunately, visit is a virtual method so I can't template it
From Modern C++ - Design Generic Programming and Design Patterns Applied - Andrei Alexandrescu
#include <iostream>
class BaseVisitor
{
public:
virtual ~BaseVisitor() {};
};
template <class T, typename R = int>
class Visitor
{
public:
virtual R visit(T &) = 0;
};
template <typename R = int>
class BaseVisitable
{
public:
typedef R ReturnType;
virtual ~BaseVisitable() {};
virtual ReturnType accept(BaseVisitor & )
{
return ReturnType(0);
}
protected:
template <class T>
static ReturnType acceptVisitor(T &visited, BaseVisitor &visitor)
{
if (Visitor<T> *p = dynamic_cast< Visitor<T> *> (&visitor))
{
return p->visit(visited);
}
return ReturnType(-1);
}
#define VISITABLE() \
virtual ReturnType accept(BaseVisitor &v) \
{ return acceptVisitor(*this, v); }
};
/** example of use */
class Visitable1 : public BaseVisitable<int>
{
/* Visitable accept one BaseVisitor */
public:
VISITABLE();
};
class Visitable2 : public BaseVisitable<int>
{
/* Visitable accept one BaseVisitor */
public:
VISITABLE();
};
class VisitorDerived : public BaseVisitor,
public Visitor<Visitable1, int>,
public Visitor<Visitable2, int>
{
public:
int visit(Visitable1 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int visit(Visitable2 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main(int argc, char **argv)
{
VisitorDerived visitor;
Visitable1 visitable1;
Visitable2 visitable2;
visitable1.accept(visitor);
visitable2.accept(visitor);
}
Is possible to avoid dynamic_cast with CRTP pattern like:
#include <iostream>
class BaseVisitor
{
public:
virtual ~BaseVisitor() {};
};
template <class T>
class Visitor
{
public:
virtual void visit(T &) = 0;
};
template <class Visitable>
class BaseVisitable
{
public:
template <typename T>
void accept(T & visitor)
{
visitor.visit(static_cast<Visitable &>(*this));
}
};
/** example of use */
class Visitable1 : public BaseVisitable<Visitable1>
{
};
class Visitable2 : public BaseVisitable<Visitable2>
{
};
class VisitorDerived : public BaseVisitor,
public Visitor<Visitable1>,
public Visitor<Visitable2>
{
public:
void visit(Visitable1 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void visit(Visitable2 & c)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main(int argc, char **argv)
{
VisitorDerived visitor;
Visitable1 visitable1;
Visitable2 visitable2;
visitable1.accept<VisitorDerived>(visitor);
visitable2.accept<VisitorDerived>(visitor);
}
Your Derived class cannot use Visitor because it hasn't been defined yet (it was only forward declared, and is therefore an incomplete type).
You can fix the compile error by putting the Visitor definition before Derived. You will also need to forward-declare Derived before defining Visitor:
template <class T> class Derived;
class Visitor {
public:
virtual void visit(Derived<string> *e) = 0;
};
template <class T>
class Derived : public Base {
//.... can call Visitor methods here ...
};