In C++11 Is there some way I can define a static member variable in a subclass that is accessed by the (abstract) base class constructor? I've unsuccessfully tried messing with initialization lists, and tried setting a non-static base class pointer to that static subclass member. I'm starting to think I'll have to write a separate constructor for each subclass just so I can do this. Any ideas?
You can pass the subclass type to the base class as a template argument:
#include <iostream>
template <typename Derived>
struct Base
{
Base()
{
std::cout << Derived::value << std::endl;
}
};
struct Foo : Base<Foo>
{
static const std::size_t value = 100;
};
struct Bar : Base<Bar>
{
static const std::size_t value = 999;
};
int main()
{
Foo baseFoo;
Bar baseBar;
}
live example
Related
I know that it isn't possible to have class methods that are both pure virtual and static (see this discussion). So, I ask: is there a way to guarantee that a bunch of derived classes have static functions that do the same thing and that are guaranteed to be named in the same way?
Consider the following example:
#include <iostream>
#include <array>
// class base {
// public:
// virtual static constexpr size_t nums() = 0
// }
template<size_t num>
class derived1 {//: public base {
public:
static constexpr size_t nums() {return num;}
derived1() {}
};
template<size_t num>
class derived2 {// : public base {
public:
static constexpr size_t nums() {return num;}
derived2() {}
};
int main() {
std::cout << derived2<20>::nums() << "\n";
return 0;
}
I commented out the base class so that it compiles, but I want an interface class that guarantees a bunch of derived classes all have nums() named in the same way. In this particular example nums is named the same way in both derived class, but if I write a third derived class a few years from now, and I forget this convention, I don't want to be able to compile anything, ideally.
You could use CRTP as the base class, and then have a routine that depends on the derived class having implemented the expected static function.
Here's an example, and I have thunk_nums in the base class dependent on the derived class having nums, although they could have been named the same.
Note that if a function isn't used, it won't be generated, and so won't trigger an error. (Which may be desired behavior, or if not desired then steps would have to be taken to ensure it is generated.)
#include <iostream>
template <typename DERIVED>
class base {
public:
static constexpr size_t thunk_nums() {
return DERIVED::nums();
}
};
template<size_t num>
class derived1 : public base<derived1<num>> {
public:
static constexpr size_t nums() {return num;}
derived1() {}
};
template<size_t num>
class derived2 : public base<derived2<num>> {
public:
static constexpr size_t nums() {return num;}
derived2() {}
};
int main() {
std::cout << derived2<20>::thunk_nums() << "\n";
}
I try to initialize a static member of a CRTP base class. The base class holds a static template member of the derived class, while the derived class defines other data members. I want to statically initialize this variable. In code, a minimal example would be the following:
template<typename DERIVED>
class base {
public:
static DERIVED x;
};
class derived : public base<derived>
{
public:
int a;
};
int base<derived>::x {0};
int main()
{}
However, the above does not compile, but gives the error message error: specializing member 'base<derived>::x' requires 'template<>' syntax.
How can I get the static initialization to work?
The correct syntax is:
template <class T>
class base {
public:
static T x;
};
template <class T>
T base<T>::x{};
Note that you can't initialize x to a specific integer value, since then your base class won't compile when DERIVED is e.g. an std::string.
You probably also want your inheritance to be explicitly public or private. I.e.:
class derived : public base<derived> {
public:
int a;
};
Edit: To specialize x and it's initialization for specific types T, you have to specialize base itself. I.e.:
class A;
template <>
class base<A> {
public:
static int x;
};
// Note missing "template <>" here.
int base<A>::x{ 5 };
class A : public base<A> { };
This seems rather cumbersome, since you need to already forward declare A in this case before declaring the specialization. To me it feels you might want to rethink your design. Is this really required or is there a simpler way to accomplish what you want?
I have found the static initializer trick, which works in the above setting, too. It was described here and here. In the above context, it would be as follows:
#include <iostream>
template<typename DERIVED>
class base {
public:
static inline DERIVED x;
};
class derived : public base<derived>
{
public:
int a;
struct static_initializer {
static_initializer()
{
derived::x.a = 1;
}
};
static inline static_initializer static_initializer_;
};
int main()
{
std::cout << derived::x.a << "\n";
}
The above output the value 1.
Note: this works with C++17.
SOLVED!
I want to create an array of different typed objects using templates.
Therefore I have a non-template class (Base), and a derived template class from Base class.
What I want to know is how can i access to derived class' generic value (T val)?
class Base{
public:
// a function returns T val, it will be implemented in Derived class
// EDIT : virtual function here
};
template<class T>
class Derived: public Base {
public:
T val;
Derived(T x) {
val = x;
}
// implementation.. it returns val
// EDIT : Implementation of virtual function
};
Solution: dynamic_cast, Note that Base class should have at least one virtual function.
Base *p[2];
p[0] = new Derived<int>(24);
p[1] = new Derived<double>(82.56);
int a = dynamic_cast<Derived<int>*>(p[0])->val; // casts p[0] to Derived<int>*
double b = dynamic_cast<Derived<double>*>(p[1])->val; // casts p[1] to Derived<double>*
cout << a << endl;
cout << b << endl;
Last time i checked, You cannot acess derived class members from a base class(non virtual).
You could modify your code this way since you are using templates.The type and value are passed to base class at construction and you can then use it.
template<typename T>
class Base {
T ini;
public:
Base(T arg){ini = arg;}
T ret(){return ini;}
};
template<class T>
class Derived: public Base<T> {
public:
T val;
Derived(T x) : Base<T>(x) {
//Base(x);
val = x;
}
// implementation.. it returns val
};
You can then instantiate it as usual and use it.
Derived<int> e(5);
e.ret();
It look like you want CRTP
The idea is to access the derived class members inside the base class. Note that you won't be able to contain an heterogeneous list of them.
template<typename D>
struct Base {
void doThings() {
// access the derived class getT function
auto var = static_cast<D&>(*this).getT();
cout << var << endl;
}
};
template<typename T>
struct Derived : Base<Derived> {
T getT() {
return myT;
}
private:
T myT;
};
I am trying to use template meta-programming to determine the base class. Is there a way to get the base class automatically without explicitly specializing for each derived class?
class foo { public: char * Name() { return "foo"; }; };
class bar : public foo { public: char * Name() { return "bar"; }; };
template< typename T > struct ClassInfo { typedef T Base; };
template<> struct ClassInfo<bar> { typedef foo Base; };
int main()
{
ClassInfo<foo>::Base A;
ClassInfo<bar>::Base B;
std::cout << A.Name(); //foo
std::cout << B.Name(); //foo
}
for right now any automatic method would need to select the first declared base and would fail for private bases.
It's possible with C++11 and decltype. For that, we'll exploit that a pointer-to-member is not a pointer into the derived class when the member is inherited from a base class.
For example:
struct base{
void f(){}
};
struct derived : base{};
The type of &derived::f will be void (base::*)(), not void (derived::*)(). This was already true in C++03, but it was impossible to get the base class type without actually specifying it. With decltype, it's easy and only needs this little function:
// unimplemented to make sure it's only used
// in unevaluated contexts (sizeof, decltype, alignof)
template<class T, class U>
T base_of(U T::*);
Usage:
#include <iostream>
// unimplemented to make sure it's only used
// in unevaluated contexts (sizeof, decltype, alignof)
template<class T, class R>
T base_of(R T::*);
struct base{
void f(){}
void name(){ std::cout << "base::name()\n"; }
};
struct derived : base{
void name(){ std::cout << "derived::name()\n"; }
};
struct not_deducible : base{
void f(){}
void name(){ std::cout << "not_deducible::name()\n"; }
};
int main(){
decltype(base_of(&derived::f)) a;
decltype(base_of(&base::f)) b;
decltype(base_of(¬_deducible::f)) c;
a.name();
b.name();
c.name();
}
Output:
base::name()
base::name()
not_deducible::name()
As the last example shows, you need to use a member that is actually an inherited member of the base class you're interested in.
There are more flaws, however: The member must also be unambiguously identify a base class member:
struct base2{ void f(){} };
struct not_deducible2 : base, base2{};
int main(){
decltype(base_of(¬_deducible2::f)) x; // error: 'f' is ambiguous
}
That's the best you can get though, without compiler support.
My solutions are not really automatic, but the best I can think of.
Intrusive C++03 solution:
class B {};
class A : public B
{
public:
typedef B Base;
};
Non-intrusive C++03 solution:
class B {};
class A : public B {};
template<class T>
struct TypeInfo;
template<>
struct TypeInfo<A>
{
typedef B Base;
};
I am not aware of any base-class-selecting template, and I'm not sure one exists or is even a good idea. There are many ways in which this breaks extensibility and goes against the spirit of inheritance. When bar publicly inherits foo, bar is a foo for all practical purposes, and client code shouldn't need to distinguish base class and derived class.
A public typedef in the base class often scratches the itches you might need to have scratched and is clearer:
class foo { public: typedef foo name_making_type; ... };
int main() {
Foo::name_making_type a;
Bar::name_making_type b;
}
What's with the base class? Are you a .NET or Java programmer?
C++ supports multiple inheritance, and also does not have a global common base class. So a C++ type may have zero, one, or many base classes. Use of the definite article is therefore contraindicated.
Since the base class makes no sense, there's no way to find it.
I am looking for a portable resolution for similar problems for months. But I don't find it yet.
G++ has __bases and __direct_bases. You can wrap them in a type list and then access any one of its elements, e.g. a std::tuple with std::tuple_element. See libstdc++'s <tr2/type_traits> for usage.
However, this is not portable. Clang++ currently has no such intrinsics.
With C++11, you can create a intrusive method to always have a base_t member, when your class only inherits from one parent:
template<class base_type>
struct labeled_base : public base_type
{
using base_t = base_type; // The original parent type
using base::base; // Inherit constructors
protected:
using base = labeled_base; // The real parent type
};
struct A { virtual void f() {} };
struct my_class : labeled_base<A>
{
my_class() : parent_t(required_params) {}
void f() override
{
// do_something_prefix();
base_t::f();
// do_something_postfix();
}
};
With that class, you will always have a parent_t alias, to call the parent constructors as if it were the base constructors with a (probably) shorter name, and a base_t alias, to make your class non-aware of the base class type name if it's long or heavily templated.
The parent_t alias is protected to don't expose it to the public. If you don't want the base_t alias is public, you can always inherit labeled_base as protected or private, no need of changing the labeled_base class definition.
That base should have 0 runtime or space overhead since its methods are inline, do nothing, and has no own attributes.
Recently when I reading Unreal Engine source code, I found a piece of code meet your requirement.
Simplified code is below:
#include <iostream>
#include <type_traits>
template<typename T>
struct TGetBaseTypeHelper
{
template<typename InternalType> static typename InternalType::DerivedType Test(const typename InternalType::DerivedType*);
template<typename InternalType> static void Test(...);
using Type = decltype(Test<T>(nullptr));
};
struct Base
{
using DerivedType = Base;
static void Print()
{
std::cout << "Base Logger" << std::endl;
}
};
struct Derived1 : Base
{
using BaseType = typename TGetBaseTypeHelper<Derived1>::Type;
using DerivedType = Derived1;
static void Print()
{
std::cout << "Derived1 Logger" << std::endl;
}
};
struct Derived2 : Derived1
{
using BaseType = typename TGetBaseTypeHelper<Derived2>::Type;
using DerivedType = Derived2;
static void Print()
{
std::cout << "Derived2 Logger" << std::endl;
}
};
int main()
{
Derived1::BaseType::Print();
Derived2::BaseType::Print();
}
Using a macro below to wrap those code make it simple:
#define DECLARE_BASE(T) \
public: \
using BaseType = typename TGetBaseTypeHelper<T>::Type; \
using DerivedType = T;
I got confused when first seeing these code. After I read #Xeo 's answer and #juanchopanza 's answer, I got the point.
Here's the keypoint why it works:
The decltype expression is part of the member declaration, which does
not have access to data members or member functions declared after
it.
For example:
In the declaration of class Derived1, when declaring Derived1::BaseType, Derived1::BaseType doesn't know the existence of Derived1::DerivedType. Because Derived1::BaseType is declared before Derived1::DerivedType. So the value of Derived1::BaseType is Base not Derived1.
I have a base class, say BassClass, with some fields, which I made them protected, and some pure virtual functions. Then the derived class, say DerivedClass, like class DerivedClass : public BassClass. Shouldn't DerivedClass inherit the protected fields from BassClass? When I tried to compile the DerivedClass, the compiler complains that DerivedClass does NOT have any of those fields, what is wrong here?
thanks
If BassClass (sic) and DerivedClass are templates, and the BassClass member you want to access from DerivedClass isn't specified as a dependent name, it will not be visible.
E.g.
template <typename T> class BaseClass {
protected:
int value;
};
template <typename T> class DerivedClass : public BaseClass<T> {
public:
int get_value() {return value;} // ERROR: value is not a dependent name
};
To gain access you need to give more information. For example, you might fully specify the member's name:
int get_value() {return BaseClass<T>::value;}
Or you might make it explicit that you're referring to a class member:
int get_value() {return this->value;}
This works:
#include <iostream>
struct Base {
virtual void print () const = 0;
protected:
int val;
};
struct Derived : Base {
void print () { std::cout << "Bases's val: " << val << std::endl; }
};