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.
Related
Suppose I have these classes:
class A
{
// virtual methods
};
template<typename T>
class B : public A
{
void ANewMethodSpecificOfClassB(...){...};
}
I would like to add a subset of B classes into a container and from there, call ANewMethodSpecificOfClassB.
For example, given:
B<instanciation1> south_park;
B<instanciatoin2> family_guy;
suppose I want to put B<instanciation1> and B<instanciation2> in the same container (for example a vector): I cannot declare a std::vector<B> because B is not a real class, only B<instanciation1> and B<instanciation2> are.
Then I thought to define a vector using a (shared) pointer to the base class. However, doing so gives error when calling ANewMethodSpecificOfClassB because the method is not defined in the base class (and no, I can't modify the base class adding the method there).
Is there a way create a container with two different instances of a template classes and call a method that all of the instantiated classes have but not the parent class of the template class?
There are (at least) two ways around this:
You might define an intermediate class, AWithSpecificMethod:
class AWithSpecificMethod {
protected:
virtual ANewMethodSpecificOfClassB() const = 0;
};
Then have B<> descend either from A or from AWithSpecificMethod. You can do that using std::conditional<>, std::is_same<> et. al.
However, this way of solving it, at some point, creates several interfaces and immediate classes which are not true abstractions, just a notation of existence of method. Also, it's virtual => likely very slow.
You might store them in an std::variant<B<T1>, B<T2>, ...> and reconsider even if A is necessary as an interface class. This works if you know the possible types T1, T2, ... that you intend to work with (practically almost always). You can visit a variant using std::visit, which you usually pass a lambda and the variant:
std::variant<B<int>, B<char>> var;
std::visit([&](auto const& actual) {
// here actual is the concrete type
// either B<int> const& or B<char>&
}, var);
I have a Base class and a Derived class. The only goal of the Base class is to make sure Derived implements a member function.
struct Base
{
virtual void f() = 0;
};
struct Derived : Base
{
void f() override final {}
};
I don't use this class polymorphically, i.e., I just instantiate objects of type Derived on the stack, like this:
Derived obj;
and I need to do this millions of times.
Edit: only a few instances exist at the same time (no stack overflow).
Is a vtable created here (during compilation time I guess)? Does it matter to me if a vtable is created or not, since I don't use it (or do I somehow)? Is there any overhead I should consider using this design? Maybe there is another way to make sure the compiler complains if Derived doesn't implement f()?
Is a vtable created here ?
Yes since you have virtual member functions.
Does it matter to me if a vtable is created or not, since I don't use it ?
Since you don't use it, it still matters in the sense that it will increase the size of your Derived structure.
Here your Derived structure is of size 8. But without the vtable, it would be of size 1.
Maybe there is another way to make sure the compiler complains if Derived doesn't implement f()?
To be honest, I think your solution using Base as an interface in order to force every derived class to implement the f() function is totally fine since it is the exact use-case for the use of interfaces.
But if the size of the Derived structure is a concern (because you said you wanted to instantiate it millions of times), perhaps you would be interested by the std::is_member_function_pointer type trait.
I have no idea about how you intend to instantiate your Derived structure so I cannot provide a code that would exactly suit your needs.
But the idea I'm thinking about is equivalent to the following (generic example):
#include <type_traits>
template <typename T>
void instantiate_a_lot_of_times(std::size_t nb_times)
{
// Check if the f() member function exists
static_assert(std::is_member_function_pointer<decltype(&T::f)>::value, "Error: The T::f() member function must be defined");
for(std::size_t i = 0; i < nb_times; ++i)
{
T t;
// Do something with t
}
}
But keep in mind that this approach has the drawback of delaying the check.
The compilation will not fail when the structure definition is encountered but when the static_assert is evaluated.
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.
I have three classes of objects:
class Foo: has a mesh, and I need to get that mesh;
class Bar: is a Foo, but has some further capabilities which Foo doesn't have;
class Baz: is a Foo, but has another completely independent set of capabilities which neither Foo nor Bar have.
All three classes need to have a way to give me their mesh which, however, can be implemented in many ways, of which I need (at the moment I can't see another way) to use at least 2 different ones, which are MeshTypeA and MeshTypeB.
I would like to have a common interface for different implementations of the same concept (getMesh), however, I can't use auto in a virtual method. I'm lacking the facility to make the code have sense. I would like to have:
class Foo
{
public:
virtual ~Foo() = 0;
virtual auto getMesh() const = 0; // doesn't compile
};
class Bar : public Foo
{
public:
virtual ~Bar() = 0;
virtual auto getMesh() const = 0; // doesn't compile
// other virtual methods
};
class ConcreteFooWhichUsesA : public Foo
{
public:
ConcreteFooWhichUsesA();
~ConcreteFooWhichUsesA();
auto getMesh() const override {return mesh_;};
private:
MeshTypeA mesh_;
};
class ConcreteBarWhichUsesB : public Bar
{
public:
ConcreteBarWhichUsesB();
~ConcreteBarWhichUsesB();
auto getMesh() const override {return mesh_;};
// other implementations of virtual methods
private:
MeshTypeB mesh_;
};
MeshTypeA and MeshTypeB are not exclusive to Foo, Bar, or Baz, which is to say all three could have both types of mesh. However I really don't care for which MeshType I get when I later use it.
Do I need to wrap MeshTypeA and MeshTypeB in my own MeshType? Is it a matter of templating the MeshType? I believe there is a way, however related questions aren't helping or I can't formulate my question in a meaningful enough way.
I have also found this where the author uses a Builder class and decltype, but I don't have such a class. Maybe that would be it? Do I need a MeshLoader sort of class as an indirection level?
If your MeshTypes all have a common (abstract) base class, then you can just return (a pointer or reference to) that in the virtual function defintions, and the derived classes can then return their concrete mesh types, and all will be well. If you have code that can work on any mesh type, it is going to need that abstract base anyways.
If your MeshTypes do not all have a common base class, why even have a getMesh method in Foo at all? Remove it and give each of the concrete classes it's own getMesh method that doesn't override (and has nothing in particular to do with the meshes in any other concrete class).
A function's return type is part of its interface. You can't just change it willy-nilly. More specifically, you cannot have a base class virtual method return one thing while an overridden version returns another. OK, you can, but only if the derived version's return type is convertible to the base class return type (in which case, calling through the base class function will perform said conversion on the overriding method's return type).
C++ is a statically typed language; the compiler must know what an expression evaluates to at compile time. Since polymorphic inheritance is a runtime property (that is, the compiler is not guaranteed to be able to know which override will be called through a base class pointer/reference), you cannot have polymorphic inheritance change compile-time constructs, like the type of a function call expression. If you call a virtual method of a base class instance, the compiler will expect this expression to evaluate to what that base class's method returns.
Remember: the point of polymorphic inheritance is that you can write code that doesn't know about the derived classes and have it still work with them. What you're trying to do violates that.
I have two related questions concerning the use of distributions inside classes.
Is there some kind of base distribution in C++ in order to use a distribution as a class member without knowing which distribution it will be? I cannot use templates (see question 2)
class Foo{
private:
// could by any distribution
std::base_distribution dist_;
};
I have another class Bar that should have a vector of Foo as a private member (std::vector<Foo>). The problem is that if Foo uses templates, then it is not possible to have a vector of different template arguments which is exactly what I want to have.
class Bar {
private:
std::vector<Foo> foo_;
};
boost::variant doesn't help either because I don't know the type of distributions. So this (for example) is not possible in my case:
class Bar{
private:
boost::variant<std::normal_distribution<>, std::uniform_real_distribution<> > dists_;
};
No, there are no base classes shared by all distribution templates. Even if there were, your intended approach wouldn't work anyway because of object slicing.
However, it should be fairly easy to create your own base class, and derive from it.
class base_distribution {};
template<typename ...Args> class normal_distribution :
public base_distribution, public std::normal_distribution<Args...> {};
template<typename ...Args> class uniform_int_distribution :
public base_distribution, public std::inform_int_distribution<Args...> {};
... and so on, for whatever distributions you want to support. You will also probably need to delegate the wrappers' constructors to their real distribution base class, for maximum transparency.
At this point, object slicing becomes a factor, so you can't just shove a base_distribution into a class, as a member, or shove it into a vector, and expect it to work. You'll have to use, at very least a
std::shared_ptr<base_distribution>
as a class member, or a container value. At this point, to wrap this up, define whatever virtual methods you need in your base_distribution class, and implement them in the template subclasses appropriately.
To my knowledge, there is no "base distribution class" or generic distribution class, in C++. You do have a RandomNumberDistribution concept, but that's obviously not the same thing.
If you want a quick-and-dirty distribution class (and I do mean dirty), I currently use something like that (.h, .cpp).
As for your second question - you might need to have your templated class inherit from a single non-templated class which you can place in your vector (you'll need to use pointer members though, to avoid data slicing).