I am facing errors when trying to do something similar as described below. Is this possible using class templates in c++.
I want to pass locally declared objects of class B and C and propagate till class A using the D class which acts as common interface for B and C interacting with A.
template<typename T1, typename T2>
Class A
{
protected:
T1 _t1;
T2 _t2;
public:
A(T1 t1 , T2 t2) : _t1(t1), _t2(t2) {}
};
class B {// do something};
class C {// do something};
template<typename M, typename N>
class D : public A<M,N>
{
public:
D(M m, N n)
{
A(m,n);
}
};
int main()
{
B objB;
C objC;
D<B,C> objD(objB, objC);
return 0;
}
}
Aside from the syntax errors (e.g. Class instead of class and parenthesis in comments) you should explicitly call the base class' constructor with the arguments you intend to pass to it
template<typename M, typename N>
class D : public A<M,N>
{
public:
D(M m, N n) : A<M,N>(m,n)
{}
};
since A does not have a default constructor.
Example here
Related
Consider the following classes:
class A {};
class B {};
class C {};
class D : public A, public B, public C {};
class E : public A, public C {};
class F : public A {};
I want to write a variable type that only accepts types which derive from both A and B (in this case only D) so that the following hold:
T var;
var = D(); // valid
var = E(); // invalid, does not derive from B
var = F(); // invalid, does not derive from B
I could do the following and use G as my type. G would act as a sort of 'type grouper'.
class G : public A, public B {};
class D : public F, public C {};
However if I want to apply this to any combination of base types or with any number of base types, I would need a large number of these type groupers. Is there a way to implement a multiple base type requirement without manually generating type groupers like I showed?
I do not have a specific use case that requires this, I am purely curious whether this is possible.
EDIT: Accidentally used F twice. Switched to G for the second time.
Similar to this answer, but using constraints and concepts in C++20.
#include <concepts>
class A {};
class B {};
class C {};
class D : public A, public B, public C {};
class E : public A, public C {};
class F : public A {};
template<class T>
concept AB = std::derived_from<T, A> && std::derived_from<T, B>;
template<AB T>
T *newAB() {
return new T;
}
int main() {
auto d = newAB<D>();
auto e = newAB<E>(); // error: 'E' does not satisfy 'AB'
auto f = newAB<F>(); // error: 'F' does not satisfy 'AB'
}
You Here is a type that references (points to) an object that derives from both A and B. The simplest barebones version is
struct AB
{
A* a;
B* b;
template <class D> AB(D* d) : a(d), b(d) {};
template <class D> AB& operator=(D* d) { a=d; b=d; return *this;}
};
Now you can have:
D d;
E e;
AB ab1(&d); // OK
AB ab2(&e); // Not OK
This can be templatized and expanded:
template <typename ... As>
struct Combine
{
std::tuple<As * ...> as;
template <class D> As(D* d) : as(replicate<sizeof...(As)>(d) {};
// etc etc --- writing `replicate` is left ans an exercise
};
One could add data hiding, accessors, static asserts, concepts, smart pointers and whatnot on top of this, but the idea is still the same. If you derive from A and B, you have an A part and a B part. Let me reference both.
Providing a pair of pointers/references to A and to B is the only reasonable interface one could expect from such a type (without knowing specific details about A and B).
Ostensibly one can also have a type that copies, rather than references.
struct CopyingAB : A, B
{
template <class D> CopyingAB(const D& d) : A(d), B(d) {};
template <class D> CopyingAB& operator=(const D& d)
{
A::operator=(d);
B::operator=(d);
return *this;
}
};
But you should never want or need this, because object slicing is a bug, not a feature.
There are probably no real use cases for the referencing/pointing version either, but it is not inherently evil in and of itself, so let it be.
If using C++11 can do this. Later versions offer some tweaks.
The closest I think you can get is using is_base_of and static_asserts, or a function which checks both with static_assert.
e.g.
#include <type_traits>
class A {};
class B {};
class C {};
template <class T>
void CheckClassesAreDerivedFromAandB()
{
static_assert(std::is_base_of<A, T>::value, "Check we are derived from A");
static_assert(std::is_base_of<B, T>::value, "Check we are derived from B");
}
template <class T>
void CheckClassesAreDerivedFromAandB(const T&)
{
static_assert(std::is_base_of<A, T>::value, "Check we are derived from A");
static_assert(std::is_base_of<B, T>::value, "Check we are derived from B");
}
class D : public A, public B, public C {};
class E : public A, public C {};
class F : public A {};
void test()
{
CheckClassesAreDerivedFromAandB<D>();
D d;
CheckClassesAreDerivedFromAandB(d);
}
You could even combine this into a factory method.
template <class T>
T* Create()
{
CheckBaseClassesAreDerivedFromAandB<T>();
return new T();
}
template <class T>
T Build()
{
CheckBaseClassesAreDerivedFromAandB<T>();
return T();
}
void test()
{
auto d = Create<D>();
auto e = Create<E>(); // compile error here
auto another_d = Build<D>();
...
}
While refactoring code for ease of making unit tests for an existing code base I found a code snippet that looks like below:
template <typename T>
class B {
public:
B(T* t) : t_(t) {}
void do_that() { t_->do_abc(); }
private:
T* t_;
};
template <typename T1, typename T2>
class A {
public:
class NA {
public:
NA(A* a) : a_(a) {}
void do_abc() { a_->do_xy(); }
private:
A* a_;
};
A(T1 t1, T2 t2) : t1_(t1), t2_(t2) {
auto na = new NA(this);
b_ = new B<NA>(na);
}
void do_this() { b_->do_that(); }
void do_xy() { t1_.do_x(); t2_.do_y(); }
private:
T1 t1_;
T2 t2_;
B<NA>* b_;
};
In short: A depends on T1, T2, and B. B depends on NA nested inside A and again, NA depends on A.
I would like to make B<NA> a template argument of class A and passing some b to A's constructor (just like for T1 and T2).
I first tried with moving NA to outside of A and making both B and NA template arguments of A but it didn't work as NA depends on A (via A* a_; and a_->do_xy();).
What should I go for?
Technically speaking, you can make NA a template:
template <class T>
class NA {
public:
NA(T* a) : a_(a) {}
void do_abc() { a_->do_xy(); }
private:
T* a_;
};
The question is, however, whether it would express correctly your design intents, or not.
With template template parameter and factory, you might do:
template <typename T1, typename T2, template <typename> class C = B>
class A {
public:
class NA
{
public:
NA(A* a) : a_(a) {}
void do_abc() { a_->do_xy(); }
private:
A* a_;
};
template <typename Factory> // or possibly std::function<C<NA>*(A*)>
A(T1 t1, T2 t2, Factory f) : t1_(t1), t2_(t2), b_(f(this)) {}
void do_this() { b_->do_that(); }
void do_xy() { t1_.do_x(); t2_.do_y(); }
private:
T1 t1_;
T2 t2_;
C<NA>* b_;
};
With usage:
auto b_factory = [](A<MyType1, MyType2>* a){
auto* na = new A<MyType1, MyType2>::NA(a);
return new B<A<MyType1, MyType2>::Na>(na);
};
MyType1 t1{/*...*/};
MyType2 t2{/*...*/};
A<MyType1, MyType2, B> a(t1, t2, b_factory)
That NA depends on A is no reason to not declare it outside of A. Just forward declare A with class A;. It is an incomplete type, but it is no problem to have a pointer that. You only need to make the definition of do_abc() after the actual definition of A. But there is no problem with having the declaration before that. Edit: This will of course make NA also depend explicitly (it did already implicitly) on T1 and T2, so you would have to use it as NA<T1, T2> in A.
Of course, you can also use template template parameters and template A with template< class T1, class T2, template<class> class B1, class NA1> (sry for the weird names, but they shouldn't shadow the classes).
I am trying to make a class that has conditional members as below (sample code to illustrate problem):
template<bool b>
struct conditional_members {};
template<>
struct conditional_members<true>
{ int m; };
template<typename T, bool b>
struct my_class : public conditional_members<b>
{
T n;
// constructor for case when b is false
my_class(T n) : n(n) {};
// constructor for case when b is true
my_class(T n, int m) : n(n), m(m) {};
};
I need to have two conditional constructors depending on the bool b but this does not compile. I tried specializing the constructors with bool value:
template<typename T>
my_class<T, true>::my_class(T n, int m) : n(n), m(m) {};
template<typename T>
my_class<T, false>::my_class(T n) : n(n) {};
but that doesn't compile either because partial function template specializations are not allowed.
Is there a way to achieve this?
The problem with
// constructor for case when b is true
my_class(T n, int m) : n(n), m(m) {};
is that a constructor's mem-initializer-list can name only virtual base classes, direct base classes, and direct non-static data members, but never an inherited member like m. This is because the member of a base class is initialized by the base class subobject constructor, so it can't be initialized again (though it could be assigned).
You can instead specify the base class initializer. With this example, conditional_members is an aggregate, so aggregate initialization will work:
// constructor for case when b is true
my_class(T n, int m) : n(n), conditional_members<b>{m} {};
Though with just that, you might get some strange side effects from the fact that my_class specializations always have the two constructors declared, even if it might be invalid to actually instantiate one constructor or the other.
Here's an SFINAE trick to make the constructors conditionally effectively invisible, depending on b:
#include <type_traits>
// Define conditional_members as before.
template<typename T, bool b>
class my_class : public conditional_members<b>
{
T n;
public:
// constructor for case when b is false
template <typename = std::enable_if_t<!b>>
my_class(T n) : n(n) {}
// constructor for case when b is true
template <typename = std::enable_if_t<b>>
my_class(T n, int m) : conditional_members<b>{m}, n(n) {}
};
As a preview, with C++20 constraints, you'll be able to write it this nice, simpler way instead:
template<typename T, bool b>
class my_class : public conditional_members<b>
{
T n;
public:
// constructor for case when b is false
my_class(T n) requires(!b) : n(n) {}
// constructor for case when b is true
my_class(T n, int m) requires(b) : conditional_members<b>{m}, n(n) {}
};
I have a base class whose constructor receives an int type named id, and several different derive class, with the same form of constructor as the base class.
Now I want to make a tuple that contains each of these elements, with its constructor receives an id determined by its index in this tuple. Like what the following dumb function does:
class Base(){
Base(int id){}
}
class Derive1, Derived2...Derivedn : public Base(){
Derive(int id):Base(id){}
}
auto make_derives_tuple()->decltype(...){
//manually write each elements' index in the tuple seems too ugly and unnecessary
return std::make_tuple(Derive1(0),Derived2(1),Derived3(2)...);
}
if the num of derived class is three:
struct Base{
Base(int id){
id_=id;
}
int id_;
};
struct Derive:public Base{
Derive(int id):Base(id){
}
};
struct Derive2:public Base{
Derive2(int id):Base(id){
}
};
auto make_derive_tuple()->decltype (std::make_tuple(Derive(0),Derive2(1),Derive3(2))){
//I want the int passed to the derived class's construor automatically generated according to it's position in the tuple
return std::make_tuple(Derive(0),Derive2(1),Derive3(2));
}
But manually write each elements's index in the tuple to pass to the constructor seems too ugly and unnecessary. Is there any elegant way of achieving this? Like using variadic template class or functions.
I don't see an elegant way to iterate over simply classes as Derived1, Derived2, Derived3, etc.
But is different if you can templatize your derive classes, adding a template index, as follows or in a similar way
template <std::size_t>
struct Derived : public Base
{ Derived (int id) : Base{id} {} };
If you can also use C++14, you can use std::make_index_sequence/std::index_sequence as follows
template <std::size_t ... Is>
auto make_helper (std::index_sequence<Is...> const &)
{ return std::make_tuple(Derived<Is+1u>{Is}...); }
template <std::size_t N>
auto make_derives_tuple ()
{ return make_helper(std::make_index_sequence<N>{}); }
The following is a full compiling example
#include <tuple>
#include <utility>
#include <type_traits>
struct Base
{ Base (int) {} };
template <std::size_t>
struct Derived : public Base
{ Derived (int id) : Base{id} {} };
template <std::size_t ... Is>
auto make_helper (std::index_sequence<Is...> const &)
{ return std::make_tuple(Derived<Is+1u>{Is}...); }
template <std::size_t N>
auto make_derives_tuple ()
{ return make_helper(std::make_index_sequence<N>{}); }
int main()
{
auto t = make_derives_tuple<3u>();
using T0 = decltype(t);
using T1 = std::tuple<Derived<1u>, Derived<2u>, Derived<3u>>;
static_assert( std::is_same<T0, T1>::value, "!" );
}
If you can't templatize (adding an index) the derived classes, the best I can imagine is pass the required derived classes as template variadic list to make_derived_tuple().
The solution become
template <typename ... Ts, std::size_t ... Is>
auto make_helper (std::index_sequence<Is...> const &)
{ return std::make_tuple(Ts{Is}...); }
template <typename ... Ts>
auto make_derives_tuple ()
{ return make_helper<Ts...>(std::index_sequence_for<Ts...>{}); }
The following is a full compiling example (where I've renamed A, B, C and D the derived classes
#include <tuple>
#include <utility>
#include <type_traits>
struct Base
{ Base (int) {} };
struct A : public Base
{ A (int id) : Base{id} {} };
struct B : public Base
{ B (int id) : Base{id} {} };
struct C : public Base
{ C (int id) : Base{id} {} };
struct D : public Base
{ D (int id) : Base{id} {} };
template <typename ... Ts, std::size_t ... Is>
auto make_helper (std::index_sequence<Is...> const &)
{ return std::make_tuple(Ts{Is}...); }
template <typename ... Ts>
auto make_derives_tuple ()
{ return make_helper<Ts...>(std::index_sequence_for<Ts...>{}); }
int main()
{
auto t = make_derives_tuple<A, B, C, D>();
using T0 = decltype(t);
using T1 = std::tuple<A, B, C, D>;
static_assert( std::is_same<T0, T1>::value, "!" );
}
Suppose I define a template T that uses a nested class of the template parameter P, as follows:
template<class P> class T
{
public:
T(P& p) : p(p) {}
P& p;
typename P::Nested& get_nested() { return p.nested; }
};
If I declare a class A that includes a nested class named Nested, I can define a variable of type T<A> with no problem:
class A
{
public:
class Nested
{
public:
int i;
};
Nested nested;
};
void test2a()
{
A a;
a.nested.i = 1;
T<A> t_a(a);
t_a.get_nested().i = 2;
}
Now, I want to declare a class B that, in the same way, includes a nested class named Nested and that inherits from T<B>, as follows:
class B : public T<B>
{
public:
class Nested
{
public:
int i;
};
Nested nested;
};
Compilation of the above code fails with error: "Nested is not a member of B"
I think I understand what's happening: at the time the template is entered, class B is incompletely defined because of inheritance.
However, I am wondering if there is any way to do such a thing...
Thanks for help.
You need to defer the resolution of the return type of get_nested until it is called.
One way to do this is to make the return type dependent on a template parameter:
template<typename unused = void>
typename std::conditional<false, unused, P>::type::Nested&
get_nested() { return p.nested; }
Another way (since C++14) is to use return type deduction:
auto& get_nested() { return p.nested; }
I was able to have your example compile with simply
template<class P> class T
{
public:
T(P& p) : p(p) {}
P& p;
auto& get_nested() { return p.nested; }
};
Another approach, exploiting the same trick as #ecatmur, but a bit simpler:
template<class R = P>
typename R::Nested& get_nested() { return p.nested; }
Similarly, here the compiler has to postpone evaluation of P::Nested until you call get_nested().