Given a templated factory method, I would like to call different constructors based on the constructors the template parameter provides:
template<typename T>
T* Factory::create()
{
if (hasOnlyDefaultConstructor<T>())
return new T();
else
return new T(this);
}
Two problems:
If T does not have a constructor T(Factory*), then there are compilation problems.
How to write hasOnlyDefaultConstructor()?
In general I would like the following:
template<typename T>
T* Factory::create()
{
if (hasDefaultConstructor<T>())
return new T();
else if (hasUnaryConstructor<T>())
return new T(create());
else if (hasBinaryConstructor<T>())
return new T(create(), create());
else ....
}
Is there a way to achieve this in C++? I understand the problems if there are multiple constructors for the compiler to choose, but let's say that we only pass types T which have exactly one public constructor.
class A
{
A(B* b);
}
class B
{
B(C* c, D* d);
}
A* a = Factory::create<A>(); // same as A* a = new A(new B());
B* b = Factory::create<B>(); // same as B* b = new B(new C(), new D());
Shouldn't it be possible to write a generic function create(), which could instantiate both B and A?
Your example is a bit strange...
I would guess that you want something like:
template<typename T>
T* Factory::create()
{
return new T();
}
template<typename T, typename P0>
T* Factory::create(P0&& p0)
{
return new T(std::forward<P0>(p0));
}
template<typename T, typename P0, typename P1>
T* Factory::create(P0&& p0, P1&& p1)
{
return new T(std::forward<P0>(p0), std::forward<P1>(p1));
}
or with variadic templates:
template<typename T, typename... Args>
T* Factory::create(Args&&... args)
{
return new T(std::forward<Args>(args)...);
}
EDIT:
Based on comment below... still wierd from a memory management view.
template<typename T>
struct factory;
template<>
struct factory<A>
{
static A* create(){return new A(new B());}
}
template<>
struct factory<B>
{
static B* create(){return new B(new C(), new D());}
}
int main()
{
A* a = factory<A>::create();
B* b = factory<B>::create();
return 0;
}
You may want this:
struct X
{
enum {TYPE = 0;}// has default constructor
X() {}
};
struct A
{
enum {TYPE = 1;}
typedef B P;
A(P* p) {}
};
struct B
{
enum {TYPE = 2;}
typedef C P1;
typedef D P2;
B(P1* p1, P2* p2) {}
};
template<T, type> //type default = 0
struct FactoryDetail<T>
{
static T* create(){return new T(); }
};
template<T>
struct FactoryDetail<T, 1>
{
static T* create(){return new T(new typename T::P()); }
};
template<T>
struct FactoryDetail<T, 2>
{
static T* create(){return new T(new typename T::P1(), new typename T::P2()); }
};
//final Factory
template<T>
struct Factory
{
static T* create(){return FactoryDetail<T, T::TYPE>::create(); }
};
I don't have dev environment now, the above codes describing the basic idea.
Related
Because the following is illegal:
struct A {
template <typename T>
virtual T* foo() = 0;
};
struct B : A {
template <typename T>
virtual T* foo() override {return new T;} // Simple example here.
};
template <typename T>
T* bar (A* a) {
return a->foo<T>(); // The need for the virtual method.
}
and the template only appears in the return type, I've thought of a (naïve?) workaround using overload:
#include <iostream>
struct Base { virtual void show() const = 0; };
struct Object : Base { virtual void show() const override {std::cout << "I am an Object.\n";} };
struct Thing : Base { virtual void show() const override {std::cout << "I am a Thing.\n";} };
struct Blob : Base { virtual void show() const override {std::cout << "I am a Blob.\n";} };
struct A {
virtual Object* foo (Object&&) = 0;
virtual Thing* foo (Thing&&) = 0;
virtual Blob* foo (Blob&&) = 0;
};
struct B : A {
virtual Object* foo (Object&&) override {return fooHelper<Object>();}
virtual Thing* foo (Thing&&) override {return fooHelper<Thing>();}
virtual Blob* foo (Blob&&) override {return fooHelper<Blob>();}
private:
template <typename T>
T* fooHelper() {return new T;} // Simple example here.
};
template <typename T>
T* bar (A* a) {
return a->foo(T{});
}
int main() {
B* b = new B;
Base* list[] = {bar<Object>(b), bar<Thing>(b), bar<Blob>(b)};
for (const Base* x : list) x->show();
}
The problem with this solution is that it is only feasible if there are not too many types for T. But what if there are? Furthermore, there is now the maintenance problem when new types for T are introduced later.
Can someone think of a better solution than this? The known visitor pattern as a virtual template workaround does not apply here (I don't think) because the template does not appear in the argument.
...
T* fooHelper() {return new T;}
};
template <typename T>
T* create (A* a) {
return a->foo(T{});
}
The instance of A has no effect on the T you return. I'm assuming maybe that's supposed to be an argument. It also seems like you want a factory. How about using a member function:
template < typename T, typename FactoryType,
typename MemFnType, typename ArgType >
T* create(FactoryType* f, MemFnType mfn, ArgType a)
{
return (f->*mfn)(a);
}
Full Example:
#include <iostream>
struct Base { virtual void show() const = 0; };
struct Object : Base { virtual void show() const override {std::cout << "I am an Object.\n";} };
struct Thing : Base { virtual void show() const override {std::cout << "I am a Thing.\n";} };
struct Blob : Base { virtual void show() const override {std::cout << "I am a Blob.\n";} };
struct Args
{
int someArg;
};
struct Factory
{
// normally 'a' would be passed to the Object constructor.
// omitted to save edits.
Object* asObject(const Args& a) { return new Object(); }
Thing* asThing(const Args& a) { return new Thing(); }
Blob* asBlob(const Args& a) { return new Blob(); }
};
template < typename T, typename FactoryType,
typename MemFnType, typename ArgType >
T* create(FactoryType& f, MemFnType mfn, ArgType& a)
{
return (&f->*mfn)(a);
}
int main() {
Args arg;
Factory f;
Base* list[] = {create<Object>(f, &Factory::asObject, arg), create<Thing>(f, &Factory::asThing, arg), create<Blob>(f, &Factory::asBlob, arg)};
for (const Base* x : list) x->show();
}
Adding constructible types just requires adding the type itself and the related factory function. You can even generalize it to a full template argument list instead of a single argument type.
I want to get pointer to base class from boost variant, if I put orignally pointer to derived class. Is there some way to achive this . The following code does not work.
class A{ public: virtual ~A(){}}; class B : public A{};
typedef boost::variant<A*,B*> MyVar;
MyVar var = new B;
A* a = boost::get<A*> (var); // the following line throws exception
Maybe someone have idea how to write my own get function which will test if the requested type is base class of the stored type of in the variant,and then do the appropriate cast
You can write your own visitor with templated operator() like below:
LIVE DEMO
#include <iostream>
#include <boost/variant.hpp>
#include <type_traits>
struct A { virtual ~A() {} virtual void foo() {} };
struct B : A { virtual void foo() { std::cout << "B::foo()" << std::endl; } };
template <typename T>
struct visitor : boost::static_visitor<T>
{
private:
using Base = typename std::remove_pointer<
typename std::remove_cv<
typename std::remove_reference<T>::type
>::type
>::type;
template <typename U>
T get(U& u, std::true_type) const
{
return u;
}
template <typename U>
T get(U& u, std::false_type) const
{
throw boost::bad_get{};
}
public:
template <typename U>
T operator()(U& u) const
{
using Derived = typename std::remove_pointer<
typename std::remove_cv<
typename std::remove_reference<U>::type
>::type
>::type;
using tag = std::integral_constant<bool
, (std::is_base_of<Base, Derived>::value
|| std::is_same<Base, Derived>::value)
&& std::is_convertible<U, T>::value>;
return get(u, tag{});
}
};
template <typename T, typename... Args>
T my_get(boost::variant<Args...>& var)
{
return boost::apply_visitor(visitor<T>{}, var);
}
int main()
{
boost::variant<A*,B*> var = new B;
A* a = my_get<A*>(var); // works!
a->foo();
B* b = my_get<B*>(var); // works!
b->foo();
}
Output:
B::foo()
B::foo()
Q & A section:
This solution is weird!
No, it is not. This is exactly what the visitor classes in Boost.Variant are for. Similar solution already exists in latest release of Boost.Variant, which is boost::polymorphic_get<T>. Sadly it was designed for other purposes and cannot be used here.
Hi thank you all for your answers and comments
I came to the following which decides at compile time if types are inherited from each other. And it seems to work, and it seems much easier to me to understand.
#include <iostream>
#include <boost/variant.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility.hpp>
using namespace boost::type_traits;
struct A { virtual ~A() {} virtual void foo() {} };
struct B : A { virtual void foo() { std::cout << "B::foo()" << std::endl; } };
typedef boost::variant<B*,A*,C*> MyVar;
template <typename A,typename B>
struct types_are_inheritance_related
{
static const bool value=
ice_or<
boost::is_base_of<A, B>::value,
boost::is_base_of<B, A>::value
>::value;
};
template<class Base>
class get_visitor
: public boost::static_visitor<Base*> { public:
template<class T>
Base* operator()( T* t, typename boost::enable_if<types_are_inheritance_related<Base,T> >::type* dummy = 0)
{
Base* b = dynamic_cast<Base*> ( t);
return b;
}
template<class T>
Base* operator()( T* t, typename boost::disable_if<types_are_inheritance_related<Base,T> >::type* dummy = 0)
{
return 0;
}
};
template<class T>
T* get_var_value(MyVar& var)
{
get_visitor<T> visitor;
T* aa= var.apply_visitor(visitor);
return aa;
}
int main()
{
MyVar var = new B;
A* a = get_var_value<A*>(var); // works!
a->foo();
B* b = get_var_value<B*>(var); // works!
b->foo();
}
In C++, I'd like to be able to do the following:
struct IWrapper {
template<typename U>
U* dynamic_cast_to() { ??? } // what to do here?
};
template<typename T>
struct Wrapper : IWrapper {
Wrapper(T* _p) :p(_p) {}
T* p;
};
With this I'd like to be able to do
SomeDerived *a = new SomeDerived;
IWrapper *x = new Wrapper<SomeDerived>(a);
SomeBase *b = x->dynamic_cast_to<SomeBase>()
dynamic_cast_to() should return a pointer if indeed SomeDerived inherits from SomeBase and NULL if not, the same way normal dynamic_cast works.
Is this even possible?
give IWrapper a virtual destructor and use dynamic_cast.
i am amazed that the question is asked, how to implement a dynamic_cast_to function.
how can one avoid considering standard dynamic_cast then?
I don't think this can be done for arbitrary types T and U. The reason is that
the compiler has to generate the dynamic_cast code for the specific pair of types at compile time,
and there is no place where both types are known simultaneously at compile time.
If you could restrict IWrapper to just work for types derived from a certain base that had a virtual member function, then it could work like this:
struct IWrapper {
template<typename U>
U* dynamic_cast_to() { return dynamic_cast<U*>(commonBasePtr()); }
virtual CommonBase* commonBasePtr() = 0;
};
template<typename T>
struct Wrapper : IWrapper {
Wrapper(T* _p) :p(_p) {}
T* p;
virtual CommonBase* commonBasePtr() { return p; }
};
Not possible like that, because IWrapper doesn't know anything about T, nor has it access to the pointer. This should work:
template <typename T>
struct IWrapper {
IWrapper(T* p) : p_(p) {}
template<typename U>
U* dynamic_cast_to() { return dynamic_cast<U*>(p_); }
private:
T* p_;
};
template<typename T>
struct Wrapper : IWrapper<T> {
Wrapper(T* _p) : IWrapper<T>(_p), p(_p) {}
T* p;
};
struct SomeBase {
int a;
};
struct SomeDerived : public SomeBase {
int b;
};
int main()
{
SomeDerived *a = new SomeDerived;
IWrapper<SomeDerived> *x = new Wrapper<SomeDerived>(a);
SomeBase *b = x->dynamic_cast_to<SomeBase>();
return b->a;
}
Consider the intention behind the following illegal C++11 code:
struct Base
{
template<typename U>
virtual U convert() = 0;
};
template<typename T>
struct Derived : Base
{
T t;
template<typename U>
virtual U convert() { return U(t); }
};
struct Any
{
Base* b;
template<typename U>
operator U() { return b->convert<U>(); }
};
int main()
{
Any a = ...;
string s = a; // s = a->b->t if T is convertible to string
// fails otherwise with compile error or runtime exception
// (either acceptable)
}
Is there a way to achieve the same or similiar effect with legal code?
(fyi the above way is illegal because templates may not be ‘virtual’)
Update:
struct Base
{
void* p;
type_info type;
};
template<typename T>
struct Derived : Base
{
Derived()
{
p = &t; // immovable
type = typeid(T);
}
T t;
};
struct Any
{
Base* b;
template<typename T = U, typename U>
operator U()
{
if (b->type != typeid(T))
throw exception();
T* t = (T*) b->p;
return U(*t);
}
};
Is this what you want?
struct Base
{
virtual void* convert(const std::type_info&) = 0;
};
template<typename T>
struct Derived : Base
{
virtual void* convert(const std::type_info& ti)
{ return typeid(T) == ti ? &t : nullptr; }
T t;
};
struct Any
{
Base* b;
template<typename U>
operator U()
{
if (auto p = b->convert(typeid(U)))
return *static_cast<U*>(p);
throw std::exception();
}
};
As the other answer says, it's hard to know exactly what you want as you've only shown invalid code, not explained what you're trying to achieve.
Edit oh I see now you want it to work for any convertible type, not just exact matches ... then no, you can't turn a type_info back into the type it represents, which would be needed for the derived type to test if the given type_info corresponded to a type that its stored type is convertible to. You need to know the correct type and specify it somehow, either explicitly or implicitly via deduction. If you then want to convert it to another type, you can do that separately:
Any a{ new Derived<int>() };
try {
char c = a; // throws
}
catch (...)
{
}
int i = a; // OK
char c = (int)a; // OK
Based on your update I think that this is what you are trying to do.
#include <typeinfo>
#include <exception>
#include <string>
template <typename T>
struct Any{
T* t;
Any():t(NULL){}
Any(const T& _t){
t=new T(_t);
}
template<typename U>
operator U(){
if(typeid(T)!=typeid(U) || t==NULL)
throw std::exception();
return *t;
}
};
int main (){
Any<std::string> a(std::string("Nothing"));
std::string b=a;
return 0;
};
If this doesn't help please explain in text not code what you are trying to achieve. It'll be useful to tell us also why you want to use those two extra classes Base and Derived.
This code doesn't compile (gives errors C2059, C2065, C2072, C2143, C2146, C2447, C2470, C4430)
But does if you change B* to an inbuild type like int.
Any ideas?
template <typename T>
class A
{
private:
struct B
{
T key;
};
B* foobar(T key);
};
template <typename T>
B* A<T>::foobar(T key)
{
B* ptr = new B;
B->key = key;
return ptr;
}
int main()
{}
You have a few errors in your method.
1) the return type's scope must be properly qualified.
2) You have to set the key if a A::<T>::B instance, not a B.
Try this:
template <typename T>
typename A<T>::B* A<T>::foobar(T key) // fix error 1)
{
B* ptr = new B();
ptr->key = key; // fix error 2)
return ptr;
}
The return type should be typename A<T>::B*, not just B*:
template<typename T>
typename A<T>::B* A<T>::foobar(T key)
{
//..
}
Note also typename keyword in the return type.