Let's assume we have something like this: An Interface for some class Foo ( 'FooInterface' ) and a container class Bar that contains derived classes from 'FooInterface'.
Now I forward a typelist of the types of the derived classes ( 'FooOne', 'FooTwo' ) to the container class and it stores an instance of them in a 'boost::hana::tuple' subsequent to a small type computation ( 'FooTuple' ).
Now how do I initialize the tuple elements with a dereferenced this-pointer, depending on the size of 'FooList' ?
MCVE (Wandbox)
#include <iostream>
#include <boost/hana.hpp>
namespace hana = boost::hana;
template <typename FooList>
class Bar;
template <typename FooList>
class FooInterface
{
public:
FooInterface(Bar<FooList>& bar) {}
public:
virtual void foo() = 0;
};
class FooOne;
class FooTwo;
using MyFooList = decltype(hana::tuple_t<FooOne, FooTwo>);
class FooOne final
: public FooInterface<MyFooList>
{
public:
FooOne(Bar<MyFooList>& bar)
: FooInterface(bar)
{}
public:
void foo() override
{
std::cout << "FooOne!\n";
}
};
class FooTwo final
: public FooInterface<MyFooList>
{
public:
FooTwo(Bar<MyFooList>& bar)
: FooInterface(bar)
{}
public:
void foo() override
{
std::cout << "FooTwo!\n";
}
};
template <typename FooList>
class Bar
{
public:
using FooTuple = typename decltype(hana::unpack(FooList(), hana::template_<hana::tuple>))::type;
FooTuple foos{ *this, *this };
};
int main()
{
Bar<MyFooList> b;
b.foos[hana::int_c<0>].foo();
b.foos[hana::int_c<1>].foo();
}
Output :
FooOne!
FooTwo!
hana::replicate is your friend.
template <typename FooList>
class Bar {
...
using FooTuple = ...;
FooTuple foos;
Bar() : foos(hana::replicate<hana::tuple_tag>(*this, hana::size_c<N>)) {}
};
Now, you have to be careful cause that'll make a copy of each *this when creating a tuple in replicate. If you want references instead, use reference_wrapper like this:
foos(hana::replicate<hana::tuple_tag>(std::ref(*this), hana::size_c<N>))
and then make sure that the constructor of each thing in FooTuple can be constructed from a reference_wrapper (which is the case if they take a reference).
Not sure if this is the simplest way - but you might try std::index_sequence to do that:
template <typename FooList>
class Bar
{
static constexpr size_t fooListSize = decltype(hana::size(std::declval<FooList>()))::value;
template <std::size_t ...I>
Bar(std::index_sequence<I...>) : foos{(I, *this)...} {}
public:
using FooTuple = typename decltype(hana::unpack(FooList(), hana::template_<hana::tuple>))::type;
Bar() : Bar(std::make_index_sequence<fooListSize>{}) {}
FooTuple foos;
};
Related
class Base
{
public:
virtual void foo() = 0;
};
class A : public Base
{
public:
void foo() override { std::cout << "A\n"; }
};
class B : public Base
{
public:
void foo() override { std::cout << "B\n"; }
};
class Registry
{
public:
static Registry& instance()
{
static Registry s_instance;
return s_instance;
}
void register_foo(Base* foo)
{
m_vec.emplace_back(foo);
}
private:
std::vector<Base*> m_vec;
};
template<typename ... T>
class Foo : public T...
{
public:
Foo()
{
Registry::instance().register_foo(this);
}
void test() { (T::foo(), ...); }
};
int main()
{
auto f1 = std::make_unique<Foo<A, B>>();
auto f2 = std::make_unique<Foo<A>>();
f1->test();
f2->test();
}
As you can see I have a Base class, class A and class B.
A and B inherit from Base.
Class Foo is a template class, which is with a variadic template.
The idea is to be able to pass class A and class B into Foo.
Then this Foo is registered in the Registry class / pushed into a vector.
The problem is the following - as you can see I can have both Foo<A> and Foo<A, B>, or Foo<B, A>.
How can I have such a vector which can accept all possible types of Foo?
How about a simple common base class?
class FooBase {
public:
virtual ~FooBase() {}
virtual void test() = 0;
};
template<typename... T>
class Foo : public FooBase, public T...
{
public:
Foo() { }
void test() override { (T::foo(), ...); }
};
int main()
{
auto f1 = std::make_unique<Foo<A, B>>();
auto f2 = std::make_unique<Foo<A>>();
std::vector<std::unique_ptr<FooBase>> foos;
foos.push_back(std::move(f1));
foos.push_back(std::move(f2));
}
A std::vector holds one type of objects. You cannot put objects of different types into the same vector (and objects created from a template with different template arguments are different types).
One option (I'd not recommend it) is having a vector that holds instances of std::any) - works, but cumbersome and inefficient to work with. Another option is a vector of pointers to a common base class and taking advantage of polymorphism. A third option is simply having sepperate vectors for each type of object.
I wanted to know if anyone knows of a way to force a class hierarchy to be constructible only by the factory, effectively prohibiting the direct use of std::make_shared outside of that factory.
In the example below I have Node as the base class and SceneNode as one of the many derived classes. Node contains a static member function create() which should be the factory and only way to create new instances of Node-derived classes.
#include <iostream>
#include <memory>
class Node {
public:
template <class T, class... Args>
static std::shared_ptr<T> create(Args&&... args)
{
static_assert(std::is_base_of<Node, T>::value, "T must derive from Node");
std::shared_ptr<T> node = std::make_shared<T>(std::forward<Args>(args)...);
return node;
}
protected:
Node() {}
};
class SceneNode : public Node {
public:
SceneNode() : Node()
{
}
};
int main() {
auto a = Node::create<SceneNode>(); // Should be the only way
auto b = std::make_shared<SceneNode>(); // Should be forbidden
}
The classic way of making your factory the only class able to instanciate a given class is to make your class constructor private, and making your factory friend of your class:
class Foo
{
friend class FooFactory;
private:
Foo() = default;
};
class FooFactory
{
public:
static Foo* CreateFoo() { return new Foo(); }
static void DestroyFoo(Foo* p_toDestroy) { delete p_toDestroy; }
};
int main()
{
// Foo foo; <== Won't compile
Foo* foo = FooFactory::CreateFoo();
FooFactory::DestroyFoo(foo);
return 0;
}
EDIT (With some inheritance):
#include <type_traits>
class Foo
{
friend class FooBaseFactory;
protected:
Foo() = default;
};
class Bar : public Foo
{
friend class FooBaseFactory;
protected:
Bar() = default;
};
class FooBaseFactory
{
public:
template <typename T>
static T* Create()
{
static_assert(std::is_base_of<Foo, T>::value, "T must derive from Foo");
return new T();
}
template <typename T>
static void Destroy(T* p_toDestroy)
{
static_assert(std::is_base_of<Foo, T>::value, "T must derive from Foo");
delete p_toDestroy;
}
};
int main()
{
// Foo foo; <== Won't compile
Foo* foo = FooBaseFactory::Create<Foo>();
FooBaseFactory::Destroy<Foo>(foo);
// Bar bar; <== Won't compile
Bar* bar = FooBaseFactory::Create<Bar>();
FooBaseFactory::Destroy<Bar>(bar);
return 0;
}
One solution to this problem is to create a type that only the factory can instantiate, and have an instance of that class be required to construct the base type. You can establish a convention where the first constructor argument for types that derive from Node is a value of or reference to that type which is fed to Node's constructor. Since it's not possible for anyone else to have a NodeKey users can't instantiate anything that derives from Node without going through the factory.
#include <memory>
#include <utility>
// Class that can only be instantiated by the factory type
class NodeKey {
private:
NodeKey() {};
friend class Factory;
};
class Factory {
public:
template<class T, class ... Args>
auto make(Args&&... args) {
auto ptr = std::make_shared<T>(NodeKey{}, std::forward<Args>(args)...);
// Finish initializing ptr
return ptr;
}
};
class Node {
public:
// Can only be called with an instance of NodeKey
explicit Node(const NodeKey &) {};
};
class Foo : public Node {
public:
// Forwards the instance
explicit Foo(const NodeKey & key) : Node(key) {};
};
int main()
{
Factory factory;
auto f = factory.make<Foo>();
}
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.
In an example below I have a pretty typical CRTP example, two different derived classes that both have a method bar. The base class has a method foo which just forwards to some derived bar method
#include <iostream>
template<typename Derived>
class Base {
public:
void foo() {
static_cast<Derived*>(this)->bar();
}
};
class DerivedA : public Base<DerivedA> {
public:
void bar() {
::std::cout << "A\n";
}
};
class DerivedB : public Base<DerivedB> {
public:
void bar() {
::std::cout << "B\n";
}
};
int main() {
DerivedA a;
DerivedB b;
a.foo();
b.foo();
}
It doesn't seem like I can have an array / vector / etc. of the base class because it would have to have a type along the lines of Base<T> where T is different
Is there some kind of convention without virtual for being able to iterate over different derived classes assuming they all have the same method (bar in this case)?
You can use Boost.Variant. For example:
typedef boost::variant<DerivedA, DerivedB> Derived;
struct BarCaller : public boost::static_visitor<void> {
template <class T>
void operator()(T& obj) {
obj.bar();
}
};
int main() {
std::vector<Derived> vec{DerivedA(), DerivedB(), DerivedA()};
BarCaller bar;
for (Derived& obj : vec) {
obj.apply_visitor(bar);
}
}
This lets you store heterogeneous types in a vector or other STL container (by using a "discriminated union"), and lets you call a specific function on all of them regardless of their not having a common ancestor or any virtual methods.
It doesn't seem like I can have an array / vector / etc. of the base class because it would have to have a type along the lines of Base<T> where T is different.
You can have a base class of Base<T> for all T, then, you can have a list/vector/array of pointers to the base class, if that works for you.
struct BaseOne
{
virtual void foo() = 0;
virtual ~BaseOne() {}
};
template<typename Derived>
class Base : struct BaseOne {
public:
void foo() {
static_cast<Derived*>(this)->bar();
}
};
and then,
int main() {
std::vector<BaseOne*> v {new DerivedA, new DerivedB };
for ( auto item : v )
item->bar();
for ( auto item : v )
delete item;
}
Is there some kind of convention without virtual for being able to iterate over different derived classes assuming they all have the same method (bar in this case)?
No, there isn't.
As per now, variant has became part of the C++17 standard and the solution to the problem can be solved by std::variant and std::visit as follows.
The template class in the example is Interface<> and use the CRTP idiom to force derived class to implement helloImpl():
#include <iostream>
#include <vector>
#include <variant>
template<typename Implementer>
struct Interface {
void hello() const {
static_cast<Implementer const *>(this)->helloImpl();
}
};
A couple of class examples with different implementations of helloImpl()
struct Hello1 : public Interface<Hello1> {
void helloImpl() const {
std::cout << "Hello1" << std::endl;
}
};
struct Hello2 : public Interface<Hello2> {
void helloImpl() const {
std::cout << "Hello2" << std::endl;
}
};
And here is how to use it to store data in a vector<> container and its traversal:
int main() {
using var_t = std::variant<Hello1, Hello2>;
std::vector<var_t> items{Hello1(), Hello1(), Hello2()};
for(auto &item: items) {
std::visit([](auto &&arg) {
arg.hello();
}, item);
}
return 0;
}
I got strange code and have to extend it. But instead of copy paste many many times i decided to create a template. But get caught by a terrible rock.
Here is an example code:
template<typename T>
class anyClass {};
template<typename T>
class Outer : public anyClass<T>
{
public:
using value_t = T;
class Inner
{
virtual void foo(value_t);
};
};
class specializer : protected Outer::Inner
{
virtual void foo(int) override {}
}
I have to extend virtual void foo(value_t) in specializer.
Example:
class specializer : protected Outer::Inner
{
virtual void foo(int) override {}
virtual void foo(float) override {}
virtual void foo(string) override {}
virtual void foo(bar) override {}
// And so on...
}
Question 1: Why works the example, although class specializer : protected Outer::Inner miss a param?
All overloadings do nearly the same. I created already the function.
template<typename anyType>
void meow( anyType )
{
/***/
}
My problem is here:
virtual void foo(anytype value) //<< replace anytype with what?
{
meow<anytype>( value );
}
I need the type Outer::value_T but i don't know how to get it.
Question 2: How can i use meow by calling foo ?
Feel free to ask for more information.
UPDATE
I looked again in the origin code and realised, that i've overlooked an important using/typedef.
The working code looks like:
class specializer : protected Outer<int, float, string, bar>::Inner //Yes a variadic-template
{
virtual void foo(int) override {}
virtual void foo(float) override {}
virtual void foo(string) override {}
virtual void foo(bar) override {}
// And so on...
}
So Question 1 is solved.
Why works the example, although class specializer : protected Outer::Inner miss a param?
The example does not work. It does not work because Outer is not a type. Also, you override multiple overloads of foo even though inner has only one foo. There are several syntax errors too. If it appears to work, then the compiler is doing something non-standard.
About your second question:
virtual void foo(anytype value) //<< replace anytype with what?
You replace it with the type whose overload you intend to override. For example, if you intend to override foo(int), then replace anytype with int.
Question 2: How can i use meow by calling foo ?
Simply call meow in foo.
You would have to make specializer a template class.
#include <iostream>
template<typename T> void meow(T x)
{
std::cout << x << std::endl;
}
template<typename T>
class anyClass {};
template<typename T>
class Outer : public anyClass<T>
{
public:
using value_t = T;
class Inner
{
virtual void foo(Outer<T>::value_t);
};
};
template<typename T>
class specializer : protected Outer<T>::Inner
{
virtual void foo(T x) override
{
meow(x);
}
};
I wonder how this would help you to change the behavior in Outer or anyClass because you have not shown code which shows where and how Inner is actually used. Without that, it's just guessing.
I have the feeling that what you are actually trying to achieve is to pass a function (or Strategy?) to you Outer class, represented by Inner in your code. That would be better done by passing it as a template argument.
template<typename T>
class anyClass {};
template<typename T, typename Inner = meow<T>>
class Outer : public anyClass<T>
{
public:
using value_t = T;
// somewhere in your code
Inner i;
i.meow( any_value );
};
You can also pass a std::function to the constructor.
template
class anyClass {};
template<typename T>
class Outer : public anyClass<T>
{
public:
using value_t = T;
Outer( std::function<void (value_t)> inner);
// somewhere in your code
i.meow( any_value );
std::function<void (value_t)> i;
};
Originally I simplyfied a little bit to much.
Here is the compileable example of my problem: http://ideone.com/9U7J1a
I removed all unconducive code. I know the design is horrible but i have no influence on it.
class bar {};
class string {};
template<typename _T>
class ModelContainer
{
public:
using value_type = _T;
class Delegate {
public:
virtual void foo( value_type value);
};
};
template< typename... _Ts >
class ModelManager__AbstractBase : protected ModelContainer< _Ts >...
{
public:
class Delegate : public ModelContainer< _Ts >::Delegate... {
public:
virtual ~Delegate( ) = default;
};
};
using ModelManager__Base = ModelManager__AbstractBase<
int,
float,
string,
bar
>;
class ModelManager : public ModelManager__Base {
/* Some functions */
};
class spezializer : ModelManager::Delegate
{
public:
virtual ~spezializer() = default;
//Uncommend to see my error
// virtual void foo( value_type value) override // << value_type unknown
// {/* Calling everytime the same method, no matter which value_type*/}
};