I have a template hierarchy, and I want it to have clone() function depending on whether template type is copy-constructible. As a first step I want to begin with additional parameter bool Clonable:
template<class T, bool Clonable>
class Base {
T t;
void foo();
virtual void bar();
virtual unique_ptr<Base> clone() const = 0; //should be only for Clonable=true
};
template<class T, bool Clonable>
class Derived : public Base<T, Clonable> {
virtual void bar() override;
virtual unique_ptr<Base> clone() const override; ////should be only for Clonable=true
};
Unfortunately, instantiation of virtual functions does not depend on whether they are called or not. So I suppose that I should go with partial specialization. However, straightforward way leads to very much of code duplication. Could anyone recommend the way to achieve this with minimum code duplication?
Unfortunately, contrary to a few of the comments here, SFINAE cannot help you here. That's because a non-template member of a template class is not considered a template, and therefore cannot be SFINAE'ed out: http://coliru.stacked-crooked.com/a/258e20a0293d93f0. The standard approach to solve this would typically to make it a template in a trivial way:
template <class U = T, std::enable_if ... >
virtual std::unique_ptr<Base> clone() const = 0;
But virtual functions can't be templates, so this doesn't work.
The way to avoid repetition in this case is to inherit from a class that conditionally has the member:
template <class Base, bool Cloneable>
struct CloneInterface;
template <class Base>
struct CloneInterface<Base, false> {};
template <class Base>
struct CloneInterface<Base, true> {
virtual unique_ptr<Base> clone() const = 0;
}
And now you just inherit:
template<class T, bool Clonable>
class Base : CloneInterface<Base<T, Clonable>, Clonable> {
T t;
void foo();
virtual void bar();
};
Notice that we inherit from a base class that is templated on the derived (the derived class in question is called Base, to make things more confusing :-) ). This technique is called CRTP and it is quite powerful as it can inject interface and implementations into classes, and as you can see can do so conditionally as well.
To get the implementation, we use CRTP again:
template <class T, bool Clonable, class D>
struct BaseHelper;
template <class T, class D>
struct BaseHelper<T, false, D> : Base<T, false> {};
template <class T, class D>
struct BaseHelper<T, true, D> : Base<T, true> {
unique_ptr<Base<T, true>> clone() override { return make_unique<D>(static_cast<D&>(*this)); }
};
template<class T, bool Clonable>
class Derived : public BaseHelper<T, Clonable, Derived<T, Clonable>> {
virtual void bar() override;
};
Related
I've got a bunch of similar interfaces. I have a class template that can implement those interfaces and implement most operations that are common to those interfaces. As a result, I use a mixin on top of those interfaces.
Unfortunately, some of those interfaces are missing some of the common methods.
struct Intf1
{
virtual void f() = 0;
};
struct Intf2 {}; // Missing f.
I want to apply a mixin
template <class T>
struct Mixin
: public T
{
virtual void f() override {};
};
to a base, exactly if the base class declares a virtual method f that the mixin overrides. So, basically I am looking for some meta-programming technique
template <template <class> class Mixin, class T> using Magic = ...;
such that Magic<Mixin, Intf1> is Mixin<Intf1> and Magic<Mixin, Intf2> is Intf2.
At the moment, I am using a separate trait to check whether a method is available in the base class, but this solution has some problems:
I have to reiterate the function signature.
I do not definitely know whether the method is virtual (though it seems, this can be done).
Due to type conversion / const-ness, I may try to override a method that does not match my method's signature perfectly.
I was hoping that there might be a better solution. If my Mixin was a class that caused a substitution failure, I'd try something like this: Godbolt.
it's impossible to detect if a function is a virtual function.
but if all pure virtual functions of T is overridden by Mixin, it works:
#include <type_traits>
struct Intf1{
virtual void f() = 0;
};
struct Intf2 {};
struct Intf3{
virtual void f2() = 0;
};
template <class T>
struct Mixin : public T{
virtual void f() {}; // don't mark 'override', it will break SFINAE.
};
template<template<typename>class MixIn, typename T, typename = void>
struct Applier{
typedef T type;
};
template<template<typename>class MixIn, typename T>
struct Applier<MixIn, T, typename std::enable_if<std::is_abstract<T>::value && std::is_abstract<MixIn<T>>::value>::type>{
typedef T type;
};
template<template<typename>class MixIn, typename T>
struct Applier<MixIn, T, typename std::enable_if<std::is_abstract<T>::value && !std::is_abstract<MixIn<T>>::value>::type>{
typedef MixIn<T> type;
};
template<template<typename>class MixIn, typename T>
using applier_t = typename Applier<MixIn, T>::type;
static_assert(std::is_same<applier_t<Mixin, Intf1>, Mixin<Intf1>>::value, "overridden");
static_assert(std::is_same<applier_t<Mixin, Intf2>, Intf2>::value, "not abstract");
static_assert(std::is_same<applier_t<Mixin, Intf3>, Intf3>::value, "not overridden");
I would like to build the following classes. Base class is defining functions to be implemented, Derived implements this interface.
template <class T, class V>
class IBase
{
public:
virtual void foo(const typename V::t_args&) =0;
};
template<class T>
struct T_args
{
T z;
};
class Derived : public IBase<double, Derived>
{
public:
typedef T_args<double> t_args;
Derived() {}
void foo(const t_args& x)
{ /* do some stuff */ }
};
Compiler is complaining about Derived as an imcomplete type; I can't understand the reason why.
Is there any mean to get this class structure right?
I'm forced to code with c++98, but I'm interested for any solution in c++11 and above.
In your base template class:
virtual void foo(const typename V::t_args&) =0;
This is referencing some inner class or type called t_args of its V template parameter. When referencing a class member, the class's definition must be complete (in order to figure out what t_args is). You are attempting to use this template class as follows:
class Derived : public IBase<double, Derived>
You're passing in Derived for your V, however its class definition is incomplete. If the template base class only referenced its V parameter, it is generally "ok". However your template requires its template parameter type to be complete, because it needs to know what the heck that t_args is, and your derived class is not complete until it's fully defined. But it cannot be fully defined until its base class is fully defined. Sort of like a chicken vs egg situation.
There is no turnkey solution to this kind of a circular reference, of sorts. The only thing that can be done is restructure the class, so your "argument" type is an independent class, rather than the derived class.
Another workaround is to use some traits class:
// The traits class
template <typename T> struct Arg;
template <class T, class V>
class IBase
{
public:
virtual ~IBase() {}
virtual void foo(const typename Arg<V>::t_args&) = 0; // V can be incomplete here
// but Arg<V> should be complete
};
// So go to define Arg<Derived>:
// Result class
template<class T>
struct T_args
{
T z;
};
// Forward declaration, Arg<V> accept incomplete type
class Derived;
// Specialization for Derived
// should not use internal of Derived as it is incomplete
template <>
struct Arg<Derived>
{
typedef T_args<double> t_args;
};
// Now definition of Derived
class Derived : public IBase<double, Derived>
{
public:
typedef Arg<Derived>::t_args t_args; // Should probably go in IBase for ease usage
Derived() {}
void foo(const t_args& x) /* override */
{ /* do some stuff */ }
};
Demo
After reading the explanation by Sam Varshavchik, here is a potential workaround of my problem by adding the t_args class in the template signature of the base class:
template <class V, class Args>
class IBase
{
public:
typedef Args t_args;
virtual void foo(const Args&) =0;
};
template<class T>
struct T_args
{
T z;
};
template <class T>
class Derived : public IBase<Derived<T>, T_args<T> >
{
public:
typedef typename Derived::IBase::t_args t_args;
Derived() {}
void foo(const t_args&)
{ /* do some stuff */ }
};
For practical reasons, I've got a class like
template <class A>
class CRTP
{
template <int (A::*Member)()>
int func(void * obj)
{
int result
// Do something with Member, like
// result = (reinterpret_cast<A*>(obj)->*Member)();
return result;
}
};
The template <void (A::*Member)()> is a requirement, it cannot be passed as an argument.
And I also have a class Base
class Base : public CRTP<Base>
{
int aMemberOfBase() {...}
};
And its derived which I want to also inherit CRTP
class Derived : public CRTP<Derived>, public Base
{
int aMemberOfDerived() {...}
};
In some member of Derived, I'll do something like
func<&Derived::aMemberOfDerived>(this);
func<&Base::aMemberOfBase>(this);
Is that possible ?
(Well, VC++ compile only the first line and don't want to read about the second one... but Derived should have the members
template <int (Base::*Member)()> int func(void * obj);
template <int (Derived::*Member)()> int func(void * obj);
which looks strange, I admit it. But the following piece of code
template <void (Base::*Member)()> int func() {return 0;}
template <void (Derived::*Member)()> int func() {return 1;}
compiles and return func<&Base::someMember>() != func<&Derived::someMember>(), because the signature of the template is not the same and can't be the same.)
I must admit that I'm not well award of what the standard says. But is the inheritance pattern I'm trying to make allowed? And if yes, why one of the line doesn't compile?
Moreover, if I declare
class Derived : public Base, public CRTP<Derived>
instead of
class Derived : public CRTP<Derived>, public Base
I get compile time error (on all the func<...>(...)), which means that there's something wrong somewhere.
On the other hand, I know that
template <class A, int (A::*Member)()> int func(void * obj)
would remove the need of a CRTP, but it's painfull to write func<Derived, &Derived::aMember>(). Is there a workaround like
template <class Class, void (Class::*Member)()> class A
{
void func(void * obj) {...(reinterpret_cast<Class*>(obj)->*Member)();...}
};
template <typename Signature> class B;
template <typename Class, typename Member>
class B<&Class::Member> : public class A<Class, &Class::Member> {};
which would allow B<&Base::Derived>().func(somePtrToBase)?
You can disambiguate by qualifying the name of the base member template. The following should work:
template <typename A> struct CRTP
{
template <int (A::*Member)()> int func();
};
struct Base : CRTP<Base>
{
int aMemberOfBase();
};
struct Derived : CRTP<Derived>, Base
{
int aMemberOfDerived();
void foo()
{
CRTP<Derived>::func<&Derived::aMemberOfDerived>();
CRTP<Base>::func<&Base::aMemberOfBase>();
}
};
I made everything public to avoid getting bogged down in access control details.
Here is my situation:
Base class, no templated type:
struct Thing
{
} ;
Templated class, extends that very base class
template <typename T> struct VertexWriter : public Thing
{
template <typename S>
bool intersects( S* otherThing )
{
// has a body, returns T or F
}
} ;
Derived class, CONCRETE type (no template)
struct Rocket : VertexWriter<VertexPNCT>
{
template <typename S>
bool intersects( S* otherThing ) ; // WANTS TO OVERRIDE
// implementation in VertexWriter<T>
} ;
But template typename<S> bool VertexWriter<T>::intersects cannot be marked virtual, because it is a template class.
There are many classes that derive from the VertexWriter<VertexPNCT> specialization, so template specializing VertexWriter<VertexPNCT> would not work.
So the normal thing to do is to provide a template specialization.
But Rocket specifies it is a VertexWriter<VertexPNCT>, so it is no longer a template class. Can it specialize OR override intersects as if it were a virtual function?
No, as you've stated you cannot use virtual functions, which would provide runtime polymorphism.
That said, depending on what leeway you have on changing the layout of your classes, you might be able to do something using CRTP.
template <typename T, typename Derived> struct VertexWriter : public Thing
{
template <typename S>
bool intersects( S* otherThing )
{
return static_cast<Derived*>(this)->insersects_impl(otherThing);
}
template<typename S>
bool insersects_impl( S* otherThing)
{
// Whatever
}
} ;
struct Rocket : VertexWriter<VertexPNCT, Rocket>
{
template <typename S>
bool intersects_impl( S* otherThing ) { ... } // WANTS TO OVERRIDE
// implementation in VertexWriter<T>
} ;
The base implementation of intersects simply forwards to the CRTP function. If the derived class overrides it, it'll use the override, but otherwise it'll fall back the default. Note, this does complicate your class hierarchy, but might accomplish what you're looking for.
No, you cannot.
Templated member functions cannot be virtual.
It doesn't matter whether VertexWriter is templated, specialized, or a normal class.
You could template VertexWriter on S and make intersects a virtual function of that class template
template <typename T, typename S> struct VertexWriter : public Thing
{
virtual bool intersects( S* otherThing )
{
// has a body, returns T or F
}
} ;
Now you can override intersects in a derived class
template<typename S>
struct Rocket : VertexWriter<VertexPNCT, S>
{
virtual bool intersects( S* otherThing ) ; // WANTS TO OVERRIDE
// implementation in VertexWriter<T>
}
class Foo1: public IFoo
{
public:
template <class T>
std::vector<T> foo()
{
return std::vector<T>();
}
};
class Foo2: public IFoo
{
public:
template <class T>
std::vector<T> foo()
{
return std::vector<T>();
}
};
How can I define a common interface class for the two implementations above, such that std::vector<T> foo() is defined for this interface? Ignore that the implementations of the functions are identical.
UPDATE:
I'm writing a Container class which represents data which is sent to me via a C api.
An instance of my Container will store data of a given type, such as Container<int>, Container<std::string> and Container<Foo>.
The C api returns the data in a very awkward manner and it is possible that this will change in the future. It is possible that I can copy the data into for example std::list or std::vector, but since so much data is passed from the C api it is not known yet if this will be OK or not.
For this reason, the Container class should be independent of how the data is actually stored. I achieve this using Getter and Setter classes which I pass into the contructor, as follows:
Container<int>(Getter1<int>(uglyCApiContainer),Setter1<int>(uglyCApiContainer));
Therefore if I abandon Getter1 and Getter2 which deals with how the C api stores data, I will only need to change the creation of Containers.
However, I have a problem with this design. The type Foo.
Foo is a complex type which contains itself a set of Containers. At the moment it looks something like this:
class Foo
{
public:
...
template <class V>
Container<V> getMember(std::string& memberName)
};
So a given Foo can have a set of containers of different types. The types of these members are know to me in advance since they are stored in a model. Foo is currently a wrapper around the ugly C api memory implementation, but I would like to separate also for Foo the memory representation as I've done for the Container.
I'm not sure how to make Foo free of its memory implementation. One idea I had was to make getMember virtual so as to introduce perhaps different implementations but this isnt possible for templated functions.
Here's a solution using tag dispatching and virtual inheritance:
#include <vector>
template<typename T> struct tag {};
template<typename T> class IFooImpl {
public:
virtual std::vector<T> getImpl(tag<T>) = 0;
};
class IFoo: public virtual IFooImpl<char>, virtual IFooImpl<int>
{
public:
template<typename T> std::vector<T> get() {
return static_cast<IFooImpl<T> *>(this)->getImpl(tag<T>{});
}
};
template<typename T>
class FooImpl: public virtual IFooImpl<T> {
public:
std::vector<T> getImpl(tag<T>) { return {}; }
};
class Foo: public IFoo, FooImpl<char>, FooImpl<int> {
};
int main() {
Foo().get<char>();
}
There's a little bit of repetition where the supported types are covered (here char and int), but that can be avoided with variadic template inheritance:
#include <vector>
template<typename T> struct tag {};
template<template<typename> class C, typename... Types> class Inherit {};
template<template<typename> class C, typename T, typename... Rest>
class Inherit<C, T, Rest...>: public C<T>, Inherit<C, Rest...> {};
template<typename T> class IFooImplV {
public:
virtual std::vector<T> getImpl(tag<T>) = 0;
};
template<typename T> class IFooImpl: public virtual IFooImplV<T> {};
template<typename... Types> class IFoo: public Inherit<IFooImpl, Types...> {
public:
template<typename T> std::vector<T> get() {
return static_cast<IFooImpl<T> *>(this)->getImpl(tag<T>{});
}
};
template<typename T> class FooImpl: public IFooImpl<T> {
public:
std::vector<T> getImpl(tag<T>) { return {}; }
};
template<typename... Types> class FooMulti:
public IFoo<Types...>, Inherit<FooImpl, Types...> {};
class Foo: public FooMulti<char, int> {};
int main() {
Foo().get<char>();
}