I am trying to make my head around CRTP and C++20. Basically, I'd like to have static inheritance that can access the derived type's typedefs and using:
template <typename Derived>
class inherit
{
public:
Derived& underlying()
{
return static_cast<Derived&>(*this);
}
Derived const& underlying() const
{
return static_cast<Derived const&>(*this);
}
};
template <typename Derived>
class tester : public inherit<Derived>
{
public:
using value_type = typename Derived::value_type;
};
class real : public tester<real>
{
public:
using value_type = int;
};
int main()
{
return 0;
}
This, as explained in some other questions on SO is not allowed as of C++14 (answers that I find refer to that standard and to C++11). My understanding is that there is no way in C++17 either (if my compiler is right).
What is the current status with C++20? Are there any better solutions with the upcoming standard?
No, it's still not allowed in C++20. And it will undoubtedly remain not being allowed in C++ so long as the derived class is incomplete until the base class template is finished being instantiated. Which will undoubtedly remain the way things are because what you want would require the compiler to compile the derived class to some degree before instantiating the base class template, and that degree of "look ahead" is just not practical. And can lead to infinite loops or other confused constructs, since derived class member declarations/definitions are expected to be able to access accessible base class declarations.
Consider the simple case of some iterator requirements. Iterators have to have a value_type (ignore the whole "iterator_traits" business for the moment; our intent is to use the default traits), which the derived class will provide. Our helper iterator CRTP base class will helpfully use the derived class value_type declaration to generate pointer, reference, and so forth. But the derived class's operator* needs to be able to return reference, which is inherited from the base class, which itself is dependent on compiling the value_type declaration in the derived class. So... which gets compiled first: the base class template instantiation or the derived class? It has to be one or the other; it can't be both at the same time.
The ultimate problem is that the CRTP is just not what we really want. What we really want is to be able to store a sequence of declarations/definitions in a centralized location, then inject them into a class as needed. IE: an actual mixin. Using inheritance of a template type that names the derived class is merely the closest tool the C++ language has to achieve that. But since inheritance and template instantiation were never intended to serve this need, there will naturally be warts associated with it.
So you will continue to have to rely on the typical alternative: using a "traits" class templated on the derived class type.
Related
I know this is a really confusing way to ask the question, so let me explain what I'm getting at. I have an interface that's very simple.
for the sake of argument, let's pretend it looks like:
class Interface
{
public:
virtual ~Interface() = default;
virtual someMethod() = 0;
};
And I have a class that is either a mixin, decorator, or CRTP, but I'm not sure what terminology applies
template< typename interface_t >
class Disablable: public interface_t
{
public:
~Disablable() override = default;
setDisable(const bool shouldDisable) { mDisabled = shouldDisable; }
someMethod() override
{
if(mDisabled) return;
interface_t::someMethod();
}
private:
bool mDisabled = true;
};
My question is how polymorphism interacts with this decorator. Suppose I want to dynamically cast from an Interface to a Disablable<Interface>, will my concrete instantiations be a Disablable<Interface>?
For example, suppose I have an implementation
class ConcreteImplementation: public Interface
{
void someMethod() override
{
std::cout << "I printed to cout" << std::endl;
}
};
And somewhere else in code I instantiate a disablable, thusly,
std::unique_ptr<Interface> pInterface(new Disablable<ConcreteImplementation>());
Is there any way to interperet pInterface as Disablable?
Basically, is this true:
dynamic_cast<Disablable<Interface>>(new Disablable<ConcreteImplementation>) != nullptr?
Asked another way, if Derived is a Base, is a Decorated<Derived> a Decorated<Base>?
Suppose I want to dynamically cast from an Interface to a Disablable<Interface>, will my concrete instantiations be a Disablable<Interface>?
Your Disablable<T> derives from T. So if you have a pointer or reference to the Interface subobject of a Disablable<Interface> object, then you can cast this Interface pointer or reference to a pointer or reference to the Disablable<Interface> instance. This only works, of course, if your Interface pointer or reference does really refer to the Interface subobject of a Disablable<Interface>.
Basically, is this true:
dynamic_cast<Disablable<Interface>>(new Disablable<ConcreteImplementation>) != nullptr?
No. ConcreteImplementation derives from Interface, not from Disablable<Interface>. Disablable<ConcreteImplementation> derives from ConcreteImplementation, which derives from Interface, not from Disablable<Interface>.
Asked another way, if Derived is a Base, is a Decorated<Derived> a Decorated<Base>?
No. Assuming that Decorated<T> derives from T, then a Decorated<Base> derives from Base. So a Decorated<Base> is a Base. A Decorated<Derived> will be a Derived, which is also a Base, but not a Decorated<Base>.
There is no special relationship or interaction between templates and runtime polymorphism. A class template is a template from which class types can be instantiated. A class template can be a template for a polymorphic class type. So instances of a class template can be polymorphic types. But that doesn't change anything about the fact that different instances of the same class template are unrelated types. If Blub is a class template, there is generally no is-a relationship between a Blub<A> and a Blub<B>, even if there was one between A and B. All that happens when Blub<A> is instantiated is that the type A is substituted into the definition of Blub. The result of that is nothing else than what you would have gotten if you had just written a new class with a corresponding definition yourself.
Apart from all that, it should probably be noted that if you find yourself wanting to perform a downcast, i.e., cast from a base pointer to a pointer to a more derived type, that should generally be taken as a clue that there may be something not optimal about the overall design…
I've written what I would hoped to be a general purpose CRTP class that allows my own classes to easily extend a class that implements a shared_from_this function (presumably returning a shared pointer equivalent to this), giving direct access to the shared pointer for the derived class instead of the base, as follows:
template<class Self, class Super>
class inherit_shared_from_this : public Super {
public:
std::shared_ptr<const Self> shared_from_this() const {
return std::static_pointer_cast<const Self>(Super::shared_from_this());
}
std::shared_ptr<Self> shared_from_this() {
return std::static_pointer_cast<Self>(Super::shared_from_this());
}
};
This works quite well for single inheritance trees, but I was wanting to extend it to be able to inherit from more than one class that implements shared_from_this. When I do so, however, I get an error 'shared_from_this' is ambiguous, because the compiler can't tell which exact class I am meaning to inherit the shared_from_this function. In fact, it does not matter which one.
What I wanted to do is define a class as follows:
class Foo : public inherit_shared_from_this<Foo, A, B, C> {
...
};
Where all of A, B, C, and D implement a shared_from_this function, and this class will publicly inherit from each of the classes other than the first, and implement exactly two shared_from_this methods, for both const and non-const versions, to return the applicable shared_pointer version of this (in this case, std::shared_ptr<Foo>).
The first thing I tried to do was adding a variadic definition for the class as follows:
template<class Self, class Super, typename... Args>
class inherit_shared_from_this : public Super, public inherit_shared_from_this<Self, Args...> {
public:
std::shared_ptr<const Self> shared_from_this() const {
return std::static_pointer_cast<const Self>(Super::shared_from_this());
}
std::shared_ptr<Self> shared_from_this() {
return std::static_pointer_cast<Self>(Super::shared_from_this());
}
};
That did not work, however... it objected that the two definitions of inherit_shared_from_this had different numbers of parameters.
Any ideas on how I can do what I am trying to accomplish, or is it just not possible?
EDIT:
A clarification on why std::shared_from_this is not usable as-is:
If I simply inherit directly from the class that inherited std::enable_shared_from_this in a derived class that also inherits from something that inherited from std::enable_shared_from_this, then it returns the wrong pointer type. If I use multiple inheritance and also inherit from std::enable_shared_from_this in a derived class whose base had extended std::enable_shared_from_this, then calling shared_from_this() in the derived class is ambiguous. Therefore a class that can inherit from such classes is required if access to the derived pointer is wanted.
EDIT:
This question differs from mine in that I am wanting to avoid adding virtual inheritance into things unless it is explicitly asked for. Since std::enable_shared_from_this itself does not have a virtual destructor in the first place, it seems improper to add that cost to what I am trying to design as a general purpose class whose purpose is to be just as reusable.
I have this particular case and would need some opinion on some of the design aspects.
Basically, I have already defined classes ( which represents position in different spaces ) and the classes does not have a concrete relationship to each other.
So, I designed a template based interpolator which can work on the currently available position representing classes.
Roughly like,
template<typename TPoint>
class Interpolator
{
.....
some function
{
TPoint::CalculateCriticalAxis(point);
}
}
As you can see, there are some static functions defined in all position classes that can be accessed inside the interpolator.
So, now since somebodyelse who need to use the interpolator and define a new position(point) class, will have to know that he needs to define them by looking at the code since there is no base class for positions.
The question is how can I design a base class which will also contain static methods which user have to override. As I understand static methods can not be overridden. So, what is the easiest way to force implementing them if somebody want to define a new position(point) class.
I do not want to redesign it since there are legacy position classes that are not from me and they non related in some sense.
Thanks!
Use a static member function, defined as deleted. A [[deprecated( "message" )]] attribute allows you to print an error message when someone tries to access a missing implementation.
// May be, but doesn't need to be a template.
struct base_interface {
// Likewise, this could be templated.
[[deprecated( "Derived class must override calculation." )]]
static value_type calculate_something() = delete;
// "Public" interface, in the vein of the non-virtual idiom (NVI).
// This must be a template, and it can't be a member - it's a friend.
template< typename derived >
friend value_type something_of( derived const & o )
{ return o.calculate_something(); }
};
The well-known weakness of "duck typing" is that the user might not try to access the missing implementation. This is a different problem. Any solution amounts to accessing all the aspects of a proper derived class.
A base class can do this, but only carefully, because there are some issues:
The derived class will be incomplete within the definition of its base class. But, it will be complete within the definitions of member functions of the base class.
The existence of a complete derived class implementation should be verified, but you don't actually want to instantiate all parts of a derived class template, much less link it into the binary. "Too much" usage will bloat compile times and executable size, respectively.
One solution is to use static_assert and decltype inside a CRTP base class constructor.
// CRTP template, derived class must pass itself to base.
template< class derived >
class base_interface {
base_interface() {
static_assert ( std::is_same< decltype( derived::calculate_something() ),
typename derived::value_type >::value,
"derived class is missing calculate_something" );
}
// Just enough to allow the static_assert condition to evaluate as false.
static struct invalid calculate_something();
typedef void value_type;
};
http://coliru.stacked-crooked.com/a/b2c5f9bf8ed58a09
Note that this is a completely different solution from the first one. This prevents the CRTP base from being trivially default constructible, but that's a fairly small price to pay. Alternately, you could put the static_asserts in a different function that is sure to be accessed, and retain the trivial default constructor.
Unfortunately, I studied class design and design patterns mostly in the context of Java; thus, I sometimes have a hard time to translate a familiar pattern to C++.
Assume we want to have a base class which's functionality is extended by a sub-class. In Java, we would do something like this:
public class BaseClass<T> {
//T is used here
protected int foo = 0;
}
public class DerivedClass<T> extends BaseClass<T> {
public void incr_foo() {
++foo;
}
}
Which I directly translated to C++:
template<class T>
class BaseClass {
protected:
size_t foo = 0;
//T is used here
};
template<class T>
class DerivedClass : public BaseClass<T> {
public:
void incr_foo() {
++(this->foo);
}
};
Since the C++ semantics of 'protected' diver from the Java-semantics, we need to use something like 'this->foo' to access protected members of the base class.
Edit: If we just use '++foo', the compiler gives the error: 'use of undeclared identifier foo'.
EditEnd
If you need to access several members of the base class, this can get a bit tedious and is not so nice to read.
Is this a good design desicion? If not, what better ways are there to achieve this?
This has nothing to do with the member being protected; you'd get the exact same error with a public member.
The real reason is that templates are involed. More specifically, that your class template has a base class which depends on a template parameter. This means that when parsing the template, the compiler will not (be able to) look into that base class to find inherited members which are used unqualified. It makes sense: when the template is parsed, the template parameter values are not known yet and thus the compiler has no idea what members the base class will have (remember partial and total specialisation exist!).
In order to overcome this, you must somehow tell the compiler that the name foo depends on template parameters (that it's a dependent name). Once you do so, the compiler will not try to resolve it when parsing the template; it will postpone resolution until the template is instantiated. At that point, template arguments are known and thus the base class can be checked.
You have three ways to mark a member name as dependent:
Refer to the name through this, as you're doing: this->foo
Refer to the name through base-class qualification: BaseClass<T>::foo
Bring the name into the scope of the derived class:
template<class T>
class DerivedClass : public BaseClass<T> {
protected:
using BaseClass<T>::foo; // from this point on, `foo` is a dependent name
public:
void incr_foo() {
++foo; // works fine now
}
};
BaseClass<T> is a dependent type - it depends on the template parameter used to instantiate DerivedClass. Until DerivedClass instantiated, the compiler doesn't know what the type is: it might be an instantiation of the generic template, or it might be an explicit specialisation, with different members.
So, within the definition of DerivedClass, there is no way to know which names refer to members of the base class. You have to specify that they are, using this-> or BaseClass::.
In a class with a non-dependent base class, you can use any accessible base-class members as if they were direct members, just as in Java.
In the example pointers/countingptr.hpp of the book C++ Templates - The Complete Guide members of the derived dependent class CountingPtr are referred to using the this pointer. Why is this necessary in this example?
I'm aware that the this pointer is required in order to name members of a dependent base class template. Surely the this pointer is not required in dependent derived class template also?
I believe it's just a style of the guy who was making this code. Some people prefer putting this-> in front of anything that is related to a class inside that class. That indeed may sometimes be useful if you are doing funny things like:
void foo( int a )
{
this->a = a;
}
or if you just think this increases readability.
However, if you use it too much, it will be a mess:
this->a = this->b * this->c - this->foo( this->d, this->bar() );
It's not needed. Some people use this everywhere.
not required in dependent derived class
In what?
There is no "dependent derived class". The derived class is the derived class.
derived class template
It is a class template, but it is parsed as a class.
Think of it this way:
It is not a class template, just a class (a type). A class template specialisation, but still a class, like a normal class.
Or this way:
The derived class template is instantiated with a "magical lazy type" argument. This lazy type argument suspends the compilation of any expression which depends on it.