Suppose I have some types
class A {…};
class B {…};
class C {…};
...
And I have some other classes that does various things on objects of these types
class process1
{
public:
void do_stuff(std::vector<A>& …);
};
class process2
{
public:
void do_stuff(std::vector<B>& …);
void do_stuff(std::vector<C>& …);
};
...
These "process" classes share some common interface (do_stuff()), so naturally I want to make an class/template to "regulate" how these classes should be written. I want to have something like
template <class T>
class process_interface
{
public:
virtual void do_stuff(std::vector<T>& …)
{
// Default implementation.
}
// I might also want this.
// virtual void do_other_stuff(std::vector<T>& …) = 0;
};
and let process1 and process2 derive from it. In this way I'm saying that all "process" classes should have a do_stuff(), and that one doesn't necessarily need to write it explicitly because there a default version.
But of course this doesn't work, because process2 has 2 versions of do_stuff(). (Some other "process" classes may have more.) So is there a way to achieve what I want to with this "interface" class/template? I was thinking using a variadic template but I suppose that won't work either.
For now what I have is this:
class process_interface
{
public:
template <class T>
void do_stuff(std::vector<T>& …)
{
// Default implementation.
}
// template <class T>
// void do_other_stuff(std::vector<T>& …)
// {
// throw std::runtime_error("Nope.");
// }
};
But it has problems. For one, do_stuff() cannot be virtual/pure virtual. And if I have other methods that need the same treatment, like the do_other_stuff() there, there's no way to force the subclasses to have a do_other_stuff() for each type that one can do_stuff() on.
Maybe you can make process2 (and all classes with need of more do_stuff() a sort of variadic self inheriting class.
Something as
template <typename...>
struct process2;
template <typename T>
struct process2<T> : public process_interface<T>
{ };
template <typename T0, typename ... Ts>
struct process2<T0, Ts...> : public process_interface<T0>,
public process2<Ts...>
{
using process_interface<T0>::do_stuff;
using process2<Ts...>::do_stuff;
};
The following is a full working example
#include <vector>
class A {};
class B {};
class C {};
class D {};
template <typename T>
struct process_interface
{
virtual void do_stuff (std::vector<T> const &)
{ }
};
struct process1 : public process_interface<A>
{ };
template <typename...>
struct process2;
template <typename T>
struct process2<T> : public process_interface<T>
{ };
template <typename T0, typename ... Ts>
struct process2<T0, Ts...> : public process_interface<T0>,
public process2<Ts...>
{
using process_interface<T0>::do_stuff;
using process2<Ts...>::do_stuff;
};
int main ()
{
process1 p1;
process2<B, C, D> p2;
p1.do_stuff(std::vector<A>{});
p2.do_stuff(std::vector<B>{});
p2.do_stuff(std::vector<C>{});
p2.do_stuff(std::vector<D>{});
}
Starting from C++17, there is no needs of a self-recursive process2: you can use unpacking using and process2 simply become
template <typename ... Ts>
struct process2 : public process_interface<Ts>...
{
using process_interface<Ts>::do_stuff ... ;
};
Use your first version and use multiple inheritance:
class process2 : process_interface<B>, process_interface<C> {
public:
using process_interface<B>::do_stuff;
using process_interface<C>::do_stuff;
};
Note the using declarations bring do_stuff in the base classes to process2 itself, so both can be found by name lookup, then participate in overload resolution.
A Complete Example
This is a great case to illustrate why common functionallity sharing is better handled through composition than inheritance.
Here's a super simple way of getting what you want without any inheritance whatsoever:
class common_interface {
template <class T>
void do_stuff(std::vector<T>& …)
{
//...
}
};
class process_1 {
common_interface common_;
public:
void do_stuff(std::vector<A>& v) {
common_.do_stuff(v);
//...
}
};
class process_2 {
common_interface common_;
public:
void do_stuff(std::vector<B>& v) {
common_.do_stuff(v);
//...
}
void do_stuff(std::vector<C>& v) {
common_.do_stuff(v);
//...
}
};
Related
I have generated a simpler example of what I am trying to accomplish. I would like to be able to call a function, which returns a class containing two template parameters, based on one of the two templated parameters (Variance).
My hierarchy can be simplified to this.
template<typename T>
class AbstractType {};
template<typename T, Variance Type>
class BaseType : public AbstractType<T> {};
template<typename T, Variance Type>
class FinalType : public BaseType<T, Type>{};
Where FinalType in this example isn't strictly necessary, it also inherits from other templated classes in my actual code, which serves no purpose in this example, so it's been removed.
Here's the example code.
enum class Variance {
Interval,
Weighted,
Constant
};
template<typename T>
class AbstractType
{
protected:
AbstractType(T* _Instance) :
Instance(_Instance) {};
T* Instance;
};
template<typename T, Variance Type>
class BaseType : public AbstractType<T>
{
protected:
BaseType(T* _Instance) :
AbstractType<T>(_Instance) {};
};
template<typename T>
class BaseType<T, Variance::Interval> : public AbstractType<T>
{
protected:
BaseType(T* _Instance) :
AbstractType<T>(_Instance) {};
int Interval;
public:
void SetInterval(int NewInterval) { Interval = NewInterval; }
};
template<typename T>
class BaseType<T, Variance::Weighted> : public AbstractType<T>
{
protected:
BaseType(T* _Instance) :
AbstractType<T>(_Instance) {};
int Weight;
public:
void SetWeight(int NewWeight) { Weight = NewWeight; }
};
template<typename T, Variance Type>
class FinalType : public BaseType<T, Type>
{
public:
FinalType(T* _Instance) :
BaseType<T, Type>(_Instance)
{};
};
struct Interface
{
template<typename T>
BaseType<T, Variance::Weighted>* CreateBaseInstance(T t, int Weight) {
FinalType<T, Variance::Weighted>* OutObj = new FinalType<T, Variance::Weighted>(t);
OutObj.SetWeight(Weight);
return OutObj;
}
template<typename T>
BaseType <T, Variance::Interval>* CreateBaseInstance(T t, int Interval) {
FinalType<T, Variance::Weighted>* OutObj = new FinalType<T, Variance::Interval>(t);
OutObj.SetInterval(20);
return OutObj;
}
};
struct Object {};
void test()
{
Interface Inter;
Object Obj;
Inter.CreateBaseInstance<Object, Variance::Weighted>(Obj, 50); // Too many template arguments
Inter.CreateBaseInstance<Object, Variance::Interval>(Obj, 10); // Too many template arguments
Inter.CreateBaseInstance<Object>(Obj, 50); // More than one instance of overloaded function
Inter.CreateBaseInstance<Object>(Obj, 10); // More than one instance of overloaded function
}
Additionally, Object being used as the first template is just for testing purposes. I will not know the type in this codebase.
I've been able to resolve this problem by creating multiple functions such as..
template<typename T>
BaseType<T, Variance::Interval>* CreateIntervalInstance(T t, int Interval)…
template<typename T>
BaseType<T, Variance::Weighted>* CreateWeightedInstance(T t, int Weight)…
template<typename T>
BaseType<T, Variance::Constant>* CreateConstantInstance(T t)…
However, as mentioned earlier, FinalType inherits from another set of classes, so while the above works, it becomes crowded and unsustainable with the number of functions needed to do the simple tasks above.
I have experimented with making the Interface have a template parameter, such as..
// Base Class
template<Variance Variant>
class Interface…
// Specialized
template<>
class Interface<Variance::Interval>…
// Functions to create Interval Instances
//Specialized
template<>
class Interface<Variance::Weighted>…
// Functions to create Weighted Instances
But, I once again run into it becoming unsustainable.
The last thing I am currently looking into is Type Traits, but am unsure if or how that could be implemented to make this simpler.
Without following all of it really in detail, don't you just want e.g.
template<typename T, Variance Type>
auto CreateBaseInstance(T t, int value) {
// Instead of `auto` maybe `std::unique_ptr<BaseType<T, Type>>`
auto OutObj = std::make_unique<FinalType<T, Type>>(t);
if constexpr(Type == Variance::Weighted) {
OutObj->SetWeight(value);
} else if constexpr(Type == Variance::Interval) {
OutObj->SetInterval(value);
}
return OutObj;
}
(I replaced new with std::make_unique, because using raw new like this is generally considered bad practice due to the memory management problems it causes.)
I have a template class Context. I want to limit the user to use the specified type (Stratege1 but not Stratege2) that is derived from a specific class Base.
class Base {
public:
virtual void run() = 0;
};
class Stratege1 : public Base {
public:
virtual void run() {
printf("Stratege1 \n");
}
};
class Stratege2 {
public:
virtual void run() {
printf("Stratege2 \n");
}
};
template <typename T> class Context {
public:
void run() {
t.run();
};
private:
T t;
};
It may be OK if the user want to invoke like this:
Context<Stratege1> context;
context.run();
However I don't expect the user use (to avoid unexpectedly potential run-time issues)
Context<Stratege2> context;
context.run();
Because Stratege2 is not derived from Base class. Is there any elegant way to limit the concept during compilation?
Thanks for any suggestions.
Since C++11, you can static_assert something, this means get a nice compilation error when a compile-time check fails:
#include <type_traits> // is_base_of
template <typename T>
class Context {
static_assert(std::is_base_of<Base, T>::value,
"T must be a derived class of Base in Context<T>.");
public:
void run() {
t.run();
};
private:
T t;
};
For instance:
Context<NotBase> c2;
error: static_assert failed "T must be a derived class of Base in Context<T>."
-> static_assert(std::is_base_of<Base, T>::value,
note: in instantiation of template class 'Context<NotBase>' requested here
-> Context<NotBase> c2;
Full program demo
Use std::enable_if_t (equivalent to std::enable_if<B,T>::type) and std::is_base_of.
#include <type_traits>
template <typename T,
typename = std::enable_if_t<std::is_base_of<Base, T>::value> >
class Context {
public:
void run() {
t.run();
};
private:
T t;
};
Is there any elegant way to limit the concept during compilation?
Another possible solution is through partial specialization: the second template paramenter is true only if T is derived from base
template <typename T, bool = std::is_base_of<Base, T>::value>
class Context;
template <typename T>
class Context<T, true>
{
private:
T t;
public:
void run () { t.run(); };
};
So you have
Context<Stratege1> cs1; // compile
// Context<Stratege2> cs2; // compilation error
Unfortunately you can hijack Context explicating the second parameter
Context<Stratege2, true> cs2; // compile
Is it possible for a specialized version of a class to share some or all functionalities of the original template class?
i.e. consider there is a template class,
template <typename T>
class A
{
A()
{}
A(const A& ref)
{}
void f1()
{
//do something
}
void f2()
{
//do something
}
void f3()
{
//do something
}
}
and it has a specialized version for a specific datatype, which only intend to add some addition functionalities to the generic version in addition the original generic functionalities.
template<>
class A<int>
{
void f4()
{
//do something
}
}
now what I specifically want is that this specialized version to be sharing everything from its generic version including the constructors if possible.
It is usually possible to implement that by restructuring the class hierarchy:
template <typename T>
class A_base
{
// All the f1() functions, et. al, implemented here
};
template<typename T> class A : public A_base<T> {
public:
// An empty shell of a class, with the constructor
// forwarding its arguments to the superclass.
template<typename ...Args> A(Args && ...args)
: A_base(std::forward<Args>(args)...)
{
}
};
template<>
class A<int> : public A_base<int>
{
// Same constructor.
void f4()
{
//do something
}
};
You end up moving all class methods, class members, into a base class, with your template class consisting of nothing more than deriving from the base class template; and an empty facade otherwise.
Then, your specialization derives from the base class the same way, and adds its own methods.
Another alternative is to implement this kind of derivation "backwards".
// Empty template class.
template<typename T> class A_extra {};
// Your specialization, with the extra method:
template<>
class A_extra<int> {
void f4()
{
}
};
// And the template class inherits from it:
template<typename T> class A : public A_extra<T> {
// Your template class
};
Depending on the particular details of your template class, one or the other approach should work; or some variation on the same theme.
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>();
}
I have a base class that is a template that looks like this:
template <typename T>
class Foo
{
public:
T bar;
};
What I'd like to do is introduce a template argument that can be used to control the access mode of the member bar.
Something like this:
template <typename T,bool publicBar=true>
class Foo
{
public:
// If publicBar is false, insert protected: here
T bar;
};
Is this possible?
Thanks.
Edit:
Many asked so, for those interesting in why I'm doing this, here's my real code!
// Class used for automatic setter/getter generation.
template <typename T,publicSetter=true>
class Property
{
public:
Property(){}
Property(T value):mObject(object){}
T operator()()const
{
return mObject;
}
public: // This is where I want the protected:
virtual void operator()(T newObject)
{
this->mObject = newObject;
}
private:
T mObject;
};
This can be done using partial template specialization:
template <typename T,bool publicBar>
class Foo
{
};
template <typename T>
class Foo<T,true>
{
public:
T bar;
};
template <typename T>
class Foo<T,false>
{
protected:
T bar;
};
The only gotcha here is that you would need to replicate the entire class for each specialization... UNLESS you wanted to make it on top of a base class, e.g.:
template <typename T>
class FooBase
{
//the goods go here
};
template <typename T,bool publicBar>
class Foo : public FooBase<T>
{
};
template <typename T>
class Foo<T,true> : public FooBase<T>
{
public:
T bar;
};
template <typename T>
class Foo<T,false> : public FooBase<T>
{
protected:
T bar;
};
Yes, this is possible using partial specialization. Whether it's advisable is a another question - for a start, this solution doesn't scale as you need 2^n specializations where n is the number of variables you're controlling the access of. And do you really want the interface of your class to change based on the value of a template parameter?
It seems like you're creating something difficult to maintain, difficult to understand and overly clever.
Nevertheless, if you decide this is a good idea, here's how you would do it:
template <typename T, bool publicBar=true>
class Foo
{
public:
T bar;
};
template <typename T>
class Foo<T,false>
{
protected:
T bar;
};
Yes, using explicit class template specialization:
template<bool B> class Foo;
template<> class Foo<true>
{
public:
int n_;
};
template<> class Foo<false>
{
protected:
int n_;
};
int main()
{
Foo<true> fa;
fa.n_;
Foo<false> fb;
fb.n_; // ERROR: protected
}
Seems like a really bad idea, though. Why would you want to?
I think you could do this with a template specialization. Totally untested code.
template <typename T,bool publicBar=true>
class Foo
{
public:
// If publicBar is false, insert protected: here
T bar;
};
template <typename T, false>
class Foo
{
protected:
// If publicBar is false, insert protected: here
T bar;
};
But really consider why you'd want to do this. public data is really dangerous for encapsulation, and protected is nearly so. A solution that's able to utilize a client-API will probably be more maintainable in the long-term.
How about
template<typename T>
struct FooBase {
T bar;
};
template<typename T, bool publicBar>
class Foo : public FooBase<T> {};
template<typename T>
class Foo<T, false> : protected FooBase<T> {};
This way you don't have to define bar a number of times but only once.