I want to write an Adapter for two different classes ClassA and ClassB - neither are mine and both have template member functions. I want to use Adapter as argument of a pure virtual member function of a class Base in order to avoid overloading of Base::do_something for ClassA and ClassB since a lot of classes will inherit from Base.
The code below is based on static polymorphism and shows how far I have got. However, extending the Adapter to work with a third class, say ClassC, always requires to change Adapter.
I wonder if there is a better way out there to write such an adapter which also can be easily extended (like in the classical adapter pattern). It would be great if someone could give me a good hint.
#include <iostream>
#include <typeinfo>
#include <variant>
template<class ...Ts>
struct overloaded : Ts...
{
overloaded(const Ts&... args) : Ts(args)... { }
using Ts::operator()...;
};
struct ClassA
{
template <class T>
std::string get_type() const {return typeid(T()).name();}
};
struct ClassB
{
template <class T>
void old_print_type() const {std::cout << typeid(T()).name();}
};
struct Adapter
{
template <class Adaptee>
Adapter (Adaptee* a) : adaptee(a) {};
template <class T>
void print_type() const
{
std::visit(overloaded(
[](ClassA* v){ std::cout << v->get_type<T>();},
[](ClassB* v){ v->old_print_type<T>();}
),adaptee);
}
using adaptee_type = std::variant<ClassA*,ClassB*>;
adaptee_type adaptee;
};
struct Base
{
virtual void do_something(const Adapter&) = 0;
virtual ~Base() = default;
};
int main()
{
ClassA a;
ClassB b;
Adapter adapterA(&a);
Adapter adapterB(&b);
adapterA.print_type<double>();
std::cout << std::endl;
adapterB.print_type<double>();
}
Related
Consider this case with multiple (implementation) inheritance with mixin pattern:
#include <string>
#include <iostream>
template <typename... Bases>
struct Overloads : public Bases... {};
struct Human {};
struct Animal {};
struct Named {
std::string name_;
void setName(const std::string& name) {
name_ = name;
}
const std::string& getName() const noexcept { return name_; }
};
template <typename OverloadsType>
struct Actor : public OverloadsType {
Actor() : OverloadsType() {}
template <typename OtherOverloads>
Actor(const Actor<OtherOverloads>& other_actor) {
// ???????
this->setName(other_actor.getName());
}
};
int main() {
Actor<Overloads<Human, Named>> named_human;
named_human.setName("Bob");
std::cout << named_human.getName() << '\n';
Actor<Overloads<Animal, Named>> named_animal;
Actor<Overloads<Animal, Named>> animal_once_a_human (named_human);
std::cout << animal_once_a_human.getName() << '\n';
}
The code works correctly, printing two Bobs: Link
I want two things
Make the conversion operator compiles even when OverloadsType and OtherOverloads aren't derived from Named (this->setName(other_actor.getName()); should be ignored or not compiled at all)
Generalize "transferring" information from (common) base classes, not only name
How can I do this?
Here's a basic blueprint. This can be further refined so that the concept actually checks that getName() return a std::string.
#include <string>
#include <iostream>
template<typename T>
concept has_a_name = requires(T &t) {
{ t.getName() };
};
template<typename T, typename U>
void give_name(const T &t, U &u)
{
}
template<has_a_name T, typename U>
void give_name(const T &t, U &u)
{
u.setName(t.getName());
}
struct tom {
std::string getName() const
{
return "Tom";
}
};
struct jerry {};
struct cartoon {
void setName(const std::string &s)
{
std::cout << s << "\n";
}
template<typename T>
cartoon(const T &t)
{
give_name(t, *this);
}
};
int main()
{
tom Tom;
jerry Jerry;
cartoon mgm{Tom}, mgm2{Jerry};
return 0;
}
As far as generalizing this goes, any possible "generic" way of defining getters and setters will either be even longer than this, or use arcane, cryptic, difficult to read templates that end up expressing very simple operations.
A simple concept that defines each class that implements a particular getter, and a pair of template functions that select a stub or the real deal, via simple overload resolution, is easy to read, understand and follow.
I want two things
Make the conversion operator compiles even when OverloadsType and OtherOverloads aren't derived from Named (this->setName(other_actor.getName()); should be ignored or not compiled at all)
Generalize "transferring" information from (common) base classes, not only name
How can I do this?
So, if the source also has the base class, it should be copied, and otherwise we should use a default constructed instance. This is straightforward.
We can define a function to extract that initializer, a copy of a base if there is one, otherwise a default constructed instance:
template <std::semiregular T, typename U>
constexpr auto extract(const U& u) -> T {
if constexpr (std::derived_from<U, T>) {
return u;
}
else {
return T();
}
}
Then we can use that to initialize the "overloads":
template <typename... Bases>
struct Overloads : public Bases... {
Overloads() = default;
template <typename OtherOverloads>
Overloads(const OtherOverloads& other_overloads) : Bases{extract<Bases>(other_overloads)}... {}
};
Then we can use that logic to initialize the actor:
template <typename OtherOverloads>
Actor(const Actor<OtherOverloads>& other_actor) : OverloadsType(other_actor) {}
See https://godbolt.org/z/ofjPb8x75
I have a variadic template class which takes two fixed template parameters and additionally a variable list of parameters.
When I create an instance I want to specify the first two parameters and have the rest deduced from the arguments passed to the ctor.
But it does not work, the variadic part seems always to be empty. I can only create an instance when I specify all the types (including the ctor arguments).
Here is the code I used for testing:
#include <iostream>
#include <tuple>
#include <string>
class Service
{
public:
virtual void Serve() = 0;
};
class InterfaceA : public Service {};
class InterfaceB : public Service {};
class InterfaceC : public Service {};
class ImplementationA : public InterfaceA
{
virtual void Serve() override
{
std::cout << "Implementation A: <null>";
}
};
class ImplementationB : public InterfaceB
{
public:
ImplementationB(int x)
: m_x(x)
{}
virtual void Serve() override
{
std::cout << "Implementation B: " << std::to_string(m_x);
}
private:
int m_x = 0;
};
class ImplementationC : public InterfaceC
{
public:
ImplementationC(std::string str)
: m_str(str)
{}
virtual void Serve() override
{
std::cout << "Implementation C: " << m_str;
}
private:
std::string m_str;
};
template <typename Interface, typename Implementation, typename... CtorArgs>
class Wrapper
{
public:
Wrapper(CtorArgs&&... args)
: m_ctorArgs(std::make_tuple(std::forward<CtorArgs>(args)...))
{}
Service& GetService()
{
m_service = std::apply([](CtorArgs ... ctorArgs)
{
return std::make_unique<Implementation>(ctorArgs...);
},
m_ctorArgs);
return *m_service;
}
private:
std::tuple<CtorArgs ...> m_ctorArgs;
std::unique_ptr<Service> m_service;
};
// deduction guide, not working...
template <typename Interface, typename Implementation, typename... CtorArgs>
Wrapper(int x)->Wrapper<Interface, Implementation, int>;
int main()
{
Wrapper<InterfaceA, ImplementationA> wrapperA;
wrapperA.GetService().Serve();
std::cout << "\n";
// Wrapper<InterfaceB, ImplementationB> wrapperB(7); // NOT OK
Wrapper<InterfaceB, ImplementationB, int> wrapperB(7); // OK
wrapperB.GetService().Serve();
std::cout << "\n";
}
I want to specify services, but create them on demand, when they are needed (due to dependencies between services). I already use factory methods in production code (wrappers which know what parameters to pass to service ctor), but in test code, I want to be able to quickly create a wrapper for mocks and dummy services, which might need different parameters as the production service.
I also tried to specify a deduction guide, but it seems to have no effect...
You might use template constructor, and std::function as factory:
template <typename Interface, typename Implementation>
class Wrapper
{
public:
template <typename... CtorArgs>
Wrapper(CtorArgs&&... args)
: m_factory([=](){return std::make_unique<Implementation>(ctorArgs...);})
{}
Service& GetService()
{
m_service = m_factory();
return *m_service;
}
private:
std::function<std::unique_ptr<Service>()> m_factory;
std::unique_ptr<Service> m_service;
};
Deduction guide is useless as it should be used to deduce all parameters.
It is all or nothing for providing template parameters.
But you could do:
Wrapper<InterfaceB, ImplementationB> wrapperB(7); // Ok
The deduction guide "should" be
template<typename Interface, typename Implementation, typename... CtorArgs>
Wrapper(CtorArgs&&... x)->Wrapper<Interface, Implementation, CtorArgs...>;
but this doesn't work, since Interface and Implementation are non-deducible.
I'd recommend following the standard library and using a factory function instead:
template<typename Interface, typename Implementation, typename... Args>
Wrapper<Interface, Implementation, Args...> make_wrapper(Args&&... args) {
return Wrapper<Interface, Implementation, Args...>(std::forward<Args>(args)...);
}
int main() {
auto wrapperA = make_wrapper<InterfaceA, ImplementationA>();
wrapperA.GetService().Serve();
std::cout << "\n";
}
Another solution is to add dummy parameters to Wrapper::Wrapper
template<typename T>
struct type_t { };
template<typename T>
constexpr inline type_t<T> type{};
template<typename Interface, typename Implementation, typename... CtorArgs>
class Wrapper {
public:
Wrapper(type_t<Interface>, type_t<Implementation>, CtorArgs&&... args)
: m_ctorArgs(std::make_tuple(std::forward<CtorArgs>(args)...))
{}
// ...
};
// not needed anymore, is implicit
// template<typename Interface, typename Implementation, typename... CtorArgs>
// Wrapper(type_t<Interface>, type_t<Implementation>, CtorArgs&&... x)->Wrapper<Interface, Implementation, CtorArgs...>;
int main() {
Wrapper wrapperB(type<InterfaceB>, type<ImplementationB>, 7);
wrapperB.GetService().Serve();
std::cout << "\n";
}
There's also this OCaml inspired thing:
template<typename Interface, typename Implementation>
struct Wrapper {
template<typename... Args>
class type {
public:
type(Args&&... args)
: m_ctorArgs(std::make_tuple(std::forward<Args>(args)...))
{}
// ...
};
};
int main() {
std::string s("Hello!");
// There's a spot of weirdness here: passing s doesn't work because then you end up trying to store a reference to s in the tuple
// perhaps the member tuple should actually be std::tuple<std::remove_cvref<Args>...>
Wrapper<InterfaceC, ImplementationC>::type wrapperC(std::move(s));
wrapperC.GetService().Serve();
std::cout << "\n";
}
Side note: Service::~Service() should probably be virtual.
So I have a tremendous number of template specializations of this template:
template <typename T> // Same
struct foo { // Same
using type_name = T; // Same
foo(const int base) : _base(base) {} // May take other parameters
void func(const T& param) {} // This function signature will be the same but body will differ
int _base; // Same but may have more members
}; // Same
So an example specialization would be:
template<>
struct foo<float> {
using type_name = T;
foo(const int base, const int child) : _base(base), _child(child) {}
void func(const T& param) { cout << param * _child << endl; }
int _base;
int _child;
};
Obviously this is a toy example and the body of _func will be more involved. But I think this expresses the idea. I can obviously make a macro to help with the boilerplate and put the implementation of the specialized version of the function in an implementation file.
But I was hoping that C++ provided me a way to do this without macros. Is there another way for me avoid writing the boilerplate over and over?
you can have multiple specialization for the function but not for the whole class
like this
#include <iostream>
#include <string>
template<typename T>
struct foo {
//common generic code
using type_name = T;
foo(const int base, const int child) : _base(base), _child(child) {}
void func(const T& param);
int _base;
int _child;
};
template<>
void foo<float>::func(const type_name&) {
//implementation
std::cout << "float" << std::endl;
}
template<>
void foo<int>::func(const type_name&) {
//implementation
std::cout << "int" << std::endl;
}
int main() {
foo<int> tint(0, 0);
foo<float> fint(0, 0);
tint.func(0);
fint.func(0);
}
You can use some light inheritance of data structs to help you separate the differences in member layout and constructor definitions from the main template.
//Define an internal aggregate type you can specialize for your various template parameters
template <typename T>
struct foo_data {
foo(const int base) : _base(base) {}
int _base;
};
//Then derive privately from the data struct (or publicly if you really desire)
template <typename T>
struct foo : private foo_data<T> {
using type_name = T;
using foo_data<T>::foo_data<T>; //Make the base class constructors visible
void func(const T& param); //Use member specialization as suggested by the other answer
};
I will leave it to you to decide if it is better this way or not, but the upshot is that all the common parts are completely separated from all the uncommon parts.
In a comment under another answer I erroneously described this as CRTP. It isn't and it doesn't have any of the drawbacks as CRTP.
If you really need to preserve standard layout, then you can simulate inheritance manually with explicit delegation and perfect forwarding.
template <typename T>
struct foo {
using type_name = T;
template <typename... Args>
foo(Args&&... args) : base_data_(std::forward<Args>(args)...) {}
void func(const T& param); //Use member specialization as suggested by the other answer
foo_data<T> base_data_;
};
One drawback is I don't think the delegating constructor will SFINAE properly as written, and it also eats noexcept specifiers and explicit. Fixing those issues(if required) is left as an exercise to the reader.
There is no nice way to avoid some redundancy in notation when implementing specializations of templated types. There are some techniques to avoid duplication of actual code, such as
Using a traits template to provide type-specific things
template<typename T>
struct foo_traits { ... }; // provide many specialisations
template<typename T> // no specialisations
struct foo
{
using traits = foo_traits<T>;
template<typename...Aars>
explicit foo(Args&&...args)
: data(std::forward<Args>(args)...) {}
int do_something_specific(T x)
{ return traits::do_something(data,x); }
private:
typename traits::data data;
};
a very similar approach is to use a specialized base class:
template<typename T>
struct foo_base { ... }; // provide many specialisations
template<typename T> // no specialisations
struct foo : foo_base<T>
{
using base = foo_base<T>;
template<typename...Aars>
explicit foo(int m, Args&&...args)
: base(std::forward<Args>(args)...)
, more_data(m) {}
int do_something_specific(T x)
{ return base::do_something(x,more_data); }
private:
int more_data;
};
The constructor of foo is a variadic template in order to allow the base class's constructor to take any number and type of arguments.
Of you can use a common base class and specialize the derived classes. This can be done with the Curiously recurring template pattern (CRTP)
template<typename Derived>
struct foo_base // no specializations
{
using type = typename Derived::type;
int do_something(type x)
{
auto result = static_cast<Derived*>(this)->specific_method(x);
return do_some_common_stuff(result);
}
protected:
foo_base(type x) : data(x) {}
type data;
private:
int do_some_common_stuff(type x)
{ /* ... */ }
};
template<typename T> // some specialisations
struct foo : foo_base<foo<T>>
{
using base = foo_base<foo>;
using type = T;
using common_type = typename base::common_type;
using base::do_something;
explicit foo(type x, type y)
: base(x), extra_data(y) {}
protected:
type specific_method(type x)
{ /* ... */ }
private:
type extra_data;
};
Note that foo_base is already a template (unlike the situation with ordinary polymorphism), so you can do a lot of specific stuff there already. Only things that are done differently (not merely with different types) need specializations of foo.
Finally, you can combine these approaches, for example traits classes with CRTP.
All these methods implement some type of static or compile-time polymorphism, rather than real or dynamic polymorphism: there are no virtual functions and hence no virtual table and no overhead for table look-up. It is all resolved at compile time.
This is usually done through inheritance - you put the immutable part into base class, and specialize the children.
I do not think you need an example for that, but let me know if you do.
Is it possible to create a class template with a member function definition only if the object created is of a specific type?
I've created a template class I will use for storing either int or doubles, but for doubles I would like to be able to set precision too (objects created with myclass < double> should have this functionality, but for myclass< int> there is no need for that to be present at all).
I know I can use a base class template, and create new classes "myInt", "myDouble" using that and implement the functionality only in the myDouble class, but I think it would be cleaner to define the functionality (both the function and a member variable) for doubles in the class template, if that's possible and preferable?
Let's add an example to show what I want to do:
#include <iostream>
#include <iomanip>
class commonBase{
public:
void setState(int state);
virtual void print() = 0;
private:
int _my_state;
};
template <typename T>
class generalObject : public commonBase {
public:
void value(T value);
void print(){ std::cout << "My value: " << _my_value << std::endl; }
private:
T _my_value;
};
template <typename T>
void generalObject<T>::value(T value){
_my_value = value;
}
// Is there any way do specialize only only whats different from the generalObject template?
// Here I thought I could specialize the case where a generalObject is created of <double>, but
// when I do, nothing is derived from generalObject (or at least not visible as far as I can tell)
template<>
class generalObject<double>{
public:
void setPrecision(int precision){ _my_precision = precision; }
// here I would like a special implementation of print(), which overrides the print() in generalObject
// and instead also prints according to the precision set when the object is of <double> type.
// Row below an example which doesn't work (compiler error, _my_value undefined)
void print(){ std::cout << "My value: " << std::setprecision(_my_precision) << _my_value << std::endl; }
private:
int _my_precision;
};
int main(int argc, char* argv[]){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1); //inherited from the commonBase
generalObject<double> o2;
o2.setPrecision(2);
o2.value(2); //here value isn't available (compile error)
o2.print();
o2.setState(123); //also isn't available (compile error)
}
Sure.
template <typename T> class Poly;
void set_precision(Poly<double>* self, int a) {};
If you really want dot notation you can then add:
template <typename T> class Poly {
public: void set_precision(int a){::set_precision(this,a);}
...
However I think you should think about what you're trying to accomplish. If MyInt and MyDouble have different fields and different methods and different implementations, they should probably be different classes.
This can be solved using template specialization.
We first define a common template...
template< typename T >
struct myclass
{
// common stuff
};
... and specialize that for double:
template<>
struct myclass<double>
{
int precision = 10;
void setprecision( int p ){ precision = p; }
};
Now the setprecision() method can only be called for myclass<double>. The compiler will complain if we try to call it for anything else, like myclass<int>.
int main()
{
myclass<double> d;
d.setprecision( 42 ); // compiles
myclass<int> i;
i.setprecision( 42 ); // fails to compile, as expected
}
Demo.
The basic way to have a member function of a class template exist only for some template parameters is to create a specialization of the class template for those template parameters.
template<typename T>class X{
// general definition
};
template<>class X<double>{
// double-specific definition
};
The downside of this is that the specialization will need to duplicate anything that is common. One way to address this is to move the common things out to a base class template:
template<typename T>class Xcommon{
// common stuff
};
template<typename T>class X: public Xcommon<T>{
// general definition
};
template<>class X<double>: public Xcommon<double>{
// double-specific definition
};
Alternatively, you can do it the other way: put the common stuff in the derived class, and the extras in the base, and specialize the base:
template<typename T>class Xextras{
// empty by default
};
template<typename T>class X: public Xextras<T>{
// common definition
};
template<>class Xextras<double>{
// double-specific definition
};
Either way can work; which is better depends on the details.
Both these methods work for data members and member functions.
Alternatively, you can use enable_if to mean that member functions are not selected by overload resolution if the template parameter doesn't meet a required condition. This requires that the member function is itself a template.
template<typename T>class X{
template<typename U=T> // make it a template,
std::enable_if<std::is_same_v<U,double>> double_specific_function(){
// do stuff
}
};
I wouldn't recommend this option unless there is no other choice.
If the question is about a member function, then here is one of the ways to do it without class template specialization:
#include <iostream>
#include <type_traits>
template <typename T>
struct Type {
template <typename U = T,
typename = typename std::enable_if<std::is_same<U, double>::value>::type>
void only_for_double() {
std::cout << "a doubling" << std::endl;
}
};
int main() {
Type<int> n;
Type<double> d;
// n.only_for_double(); // does not compile.
d.only_for_double();
}
Example on ideone.com
If you require a data-member presence based on the template parameter, you will have to do some kind of specialization, in which case it is, probably, simpler to put the function into corresponding specialization.
EDIT: After OP made his question more specific
Here is one way to do it without extra class and getting rid of virtual functions. Hope it helps.
#include <iostream>
#include <iomanip>
template <typename T, typename Derived = void>
class commonBase {
public:
void setState(int state) {
_my_state = state;
}
void value(T value) {
_my_value = value;
}
template <typename U = Derived,
typename std::enable_if<std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
std::cout << "My value: " << _my_value << std::endl;
}
template <typename U = Derived,
typename std::enable_if<!std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
static_cast<Derived const *>(this)->_print();
}
protected:
T _my_value;
int _my_state;
};
template <typename T>
class generalObject : public commonBase<T> {
};
template<>
class generalObject<double> : public commonBase<double, generalObject<double>> {
private:
friend commonBase<double, generalObject<double>>;
void _print() const {
std::cout << "My value: " << std::setprecision(_my_precision) <<
_my_value << std::endl;
}
public:
void setPrecision(int precision){ _my_precision = precision; }
private:
int _my_precision;
};
int main(){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1);
generalObject<double> o2;
o2.setPrecision(2);
o2.value(1.234);
o2.print();
o2.setState(123);
}
Same code on ideone.com
The concept of variadic templates is quite confusing to me and I want to make it a bit more complex (well I think...).
Let us consider the following code:
template <typename T>
class base
{
template <typename... E>
virtual void variadic_method_here(E... args) = 0;
};
and an implementing class:
class derive : public base<some_object>
{
void variadic_method_here(concrete_args_here);
};
How do I do that?
I think if I were faced with this problem I'd use CRTP and overloads to solve the problem.
e.g.:
#include <iostream>
template <typename Impl>
class base {
public:
template <typename... E>
void foo(E... args) {
Impl::foo_real(args...);
}
};
class derived : public base<derived> {
public:
static void foo_real(double, double) {
std::cout << "Two doubles" << std::endl;
}
static void foo_real(char) {
std::cout << "Char" << std::endl;
}
};
int main() {
derived bar;
bar.foo(1.0,1.0);
bar.foo('h');
}
You can't have a templated virtual function.