Purpose:
Storing void* instead of a concrete type is a commonly used compilation firewall technique to
reduce template instantiations and the number of symbols in compiled binaries. For example,
with a template class that stores a T* pointer to some data, member functions are instantiated
for each template combination; if instead some member functions along with a void* were
part of a non-template base class, those member functions are instantiated only once.
On memory constrained embedded platforms, a common approach to achieve run-time memory savings is to ensure common code paths. Type erasure is helpful to achieve common code paths. To save memory, it is desirable to evaluate code at compile time to the maximal extent. To keep code common between compile time and run-time, limited type erasure is required at compile time.
On memory constrained embedded platforms, a common approach to achieve run-time memory savings is to ensure common code paths. Type erasure is helpful to achieve common code paths. To save memory, it is desirable to evaluate code at compile time to the maximal extent. To keep code common between compile time and run-time, limited type erasure is required at compile time.
struct A {
virtual void f() {};
int a;
};
struct B {
int b;
};
struct C : B, A {}; // C inherits B first, then A
int main() {
C c;
void* v = &c;
// static_cast<B*>(v) is UB; should static_cast to most derived type then
// static_cast to base type.
assert(static_cast<B*>(v) == static_cast<B*>(static_cast<C*>(v)));
}
#include <string_view>
struct Sheep {
constexpr std::string_view speak() const noexcept {
return "Baaaaaa";
}
};
struct Cow {
constexpr std::string_view speak() const noexcept {
return "Mooo";
}
};
class Animal_View {
private:
const void* animal;
std::string_view (*speak_function)(const void*);
public:
template <typename Animal>
constexpr Animal_View(const Animal& a)
: animal{&a}, speak_function{[](const void* object) {
return static_cast<const Animal*>(object)->speak();
}} {}
constexpr std::string_view speak() const noexcept {
return speak_function(animal);
}
};
// This is the key bit here. This is a single concrete function
// that can take anything that happens to have the "Animal_View" interface
std::string_view do_speak(Animal_View av) {
return av.speak();
}
int main() {
// A Cow is a cow. The only thing that makes it special
// is that it has a "std::string_view speak() const" member
constexpr Cow cow;
// cannot be constexpr because of static_cast
[[maybe_unused]] auto result = do_speak(cow);
return static_cast<int>(result.size());
}
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.