How to avoid undefined behaviour with aligned_storage and polymorphism - c++

I have some code that basically do this:
struct Base {
virtual ~Base() = default;
virtual int forward() = 0;
};
struct Derived : Base {
int forward() override {
return 42;
}
};
typename std::aligned_storage<sizeof(Derived), alignof(Derived)>::type storage;
new (&storage) Derived{};
auto&& base = *reinterpret_cast<Base*>(&storage);
std::cout << base.forward() << std::endl;
I highly doubt it's well defined behaviour. If it's indeed undefined behaviour, how can I fix it? In the code that do the reinterpret_cast, I only know the type of the base class.
On the other hand, if it's well defined behavior in all cases, why is this working and how?
Just keeping a reference to the contained object is not applicable here. In my code I want to apply SBO on a type erased list where the type is created by the user of my library, and basically extends the Base class.
I add elements inside a template function, but in the function that reads it, I cannot know the Derived type. The whole reason why I use a base class is because I only need the forward function in my code that reads it.
Here's what my code looks like:
union Storage {
// not used in this example, but it is in my code
void* pointer;
template<typename T>
Storage(T t) noexcept : storage{} {
new (&storage) T{std::move(t)}
}
// This will be the only active member for this example
std::aligned_storage<16, 8> storage = {};
};
template<typename Data>
struct Base {
virtual Data forward();
};
template<typename Data, typename T>
struct Derived : Base<Data> {
Derived(T inst) noexcept : instance{std::move(inst)} {}
Data forward() override {
return instance.forward();
}
T instance;
};
template<typename> type_id(){}
using type_id_t = void(*)();
std::unordered_map<type_id_t, Storage> superList;
template<typename T>
void addToList(T type) {
using Data = decltype(type.forward());
superList.emplace(type_id<Data>, Derived<Data, T>{std::move(type)});
}
template<typename Data>
auto getForwardResult() -> Data {
auto it = superList.find(type_id<Data>);
if (it != superList.end()) {
// I expect the cast to be valid... how to do it?
return reinterpret_cast<Base<Data>*>(it->second.storage)->forward();
}
return {};
}
// These two function are in very distant parts of code.
void insert() {
struct A { int forward() { return 1; } };
struct B { float forward() { return 1.f; } };
struct C { const char* forward() { return "hello"; } };
addToList(A{});
addToList(B{});
addToList(C{});
}
void print() {
std::cout << getForwardResult<int>() << std::endl;
std::cout << getForwardResult<float>() << std::endl;
std::cout << getForwardResult<const char*>() << std::endl;
}
int main() {
insert();
print();
}

Not sure about the exact semantics of whether reinterpret_cast is required to work with base class types, but you can always do this,
typename std::aligned_storage<sizeof(Derived), alignof(Derived)>::type storage;
auto derived_ptr = new (&storage) Derived{};
auto base_ptr = static_cast<Base*>(derived_ptr);
std::cout << base_ptr->forward() << std::endl;
Also why use the auto&& with the base reference in your code?
If you only know the type of the base class in your code then consider using a simple trait in an abstraction for the aligned_storage
template <typename Type>
struct TypeAwareAlignedStorage {
using value_type = Type;
using type = std::aligned_storage_t<sizeof(Type), alignof(Type)>;
};
and then you can now use the storage object to get the type it represents
template <typename StorageType>
void cast_to_base(StorageType& storage) {
using DerivedType = std::decay_t<StorageType>::value_type;
auto& derived_ref = *(reinterpret_cast<DerivedType*>(&storage));
Base& base_ref = derived_ref;
base_ref.forward();
}
If you want this to work with perfect forwarding, then use a simple forwarding trait
namespace detail {
template <typename TypeToMatch, typename Type>
struct MatchReferenceImpl;
template <typename TypeToMatch, typename Type>
struct MatchReferenceImpl<TypeToMatch&, Type> {
using type = Type&;
};
template <typename TypeToMatch, typename Type>
struct MatchReferenceImpl<const TypeToMatch&, Type> {
using type = const Type&;
};
template <typename TypeToMatch, typename Type>
struct MatchReferenceImpl<TypeToMatch&&, Type> {
using type = Type&&;
};
template <typename TypeToMatch, typename Type>
struct MatchReferenceImpl<const TypeToMatch&&, Type> {
using type = const Type&&;
};
}
template <typename TypeToMatch, typename Type>
struct MatchReference {
using type = typename detail::MatchReferenceImpl<TypeToMatch, Type>::type;
};
template <typename StorageType>
void cast_to_base(StorageType&& storage) {
using DerivedType = std::decay_t<StorageType>::value_type;
auto& derived_ref = *(reinterpret_cast<DerivedType*>(&storage));
typename MatchReference<StorageType&&, Base>::type base_ref = derived_ref;
std::forward<decltype(base_ref)>(base_ref).forward();
}
If you are using type erasure to create your derived class types which you then add to a homogenous container, you could do something like this
struct Base {
public:
virtual ~Base() = default;
virtual int forward() = 0;
};
/**
* An abstract base mixin that forces definition of a type erasure utility
*/
template <typename Base>
struct GetBasePtr {
public:
Base* get_base_ptr() = 0;
};
template <DerivedType>
class DerivedWrapper : public GetBasePtr<Base> {
public:
// assert that the derived type is actually a derived type
static_assert(std::is_base_of<Base, std::decay_t<DerivedType>>::value, "");
// forward the instance to the internal storage
template <typename T>
DerivedWrapper(T&& storage_in) {
new (&this->storage) DerivedType{std::forward<T>(storage_in)};
}
Base* get_base_ptr() override {
return reinterpret_cast<DerivedType*>(&this->storage);
}
private:
std::aligned_storage_t<sizeof(DerivedType), alignof(DerivedType)> storage;
};
// the homogenous container, global for explanation purposes
std::unordered_map<IdType, std::unique_ptr<GetBasePtr<Base>>> homogenous_container;
template <typename DerivedType>
void add_to_homogenous_collection(IdType id, DerivedType&& object) {
using ToBeErased = DerivedWrapper<std::decay_t<DerivedType>>;
auto ptr = std::unique_ptr<GetBasePtr<Base>>{
std::make_unique<ToBeErased>(std::forward<DerivedType>(object))};
homogenous_container.insert(std::make_pair(id, std::move(ptr)));
}
// and then
homogenous_container[id]->get_base_ptr()->forward();

You may simply do
auto* derived = new (&storage) Derived{};
Base* base = derived;
So no reinterpret_cast.

In the 'simple' exmaple you have, since you are casting from derived to base, either static_cast or dynamic_cast will work.
The more complex use case will end in tears, because the underlying values of a base pointer and a derived pointer to the same object need not be equal. It might work today, but fail tomorrow:
reinterpret_cast does not play well with inheritance, especially multiple inheritance. If you ever to inherit from multiple basesand the first base class has size (or not have size if empty base optimization is not performed), reinterpret_cast to the second base class from an unrelated type will not apply the offset.
Overloading does not play well with overriding. Templated classes should not have virtual methods. Templated classes with virtual methods should not be used with too much type deduction.
The undefined behavior is fundamental to the manner in which MI is specified in C++, and unavoidable because you are trying to obtain something (in compile time) that you deliberated erased (in compile time). Just drop every virtual keyword from that class and implement everything with templates and everything will be more simple and correct.
Are you sure your derived class objects can fit within 16 bytes? You probably need some static_assert.
If you are willing to stomach the performance penalty introduced by virtual functions, why care about alignment?

Related

Can a function return a type?

I was wondering if there was any way to do something like this in C++:
$(some typename) func() {
if (/*condition*/) return int;
else return bool;
}
Edit: I think I wasn't clear enough. I was wondering if you could say something like this: func() var = /*something*/. Basically, the function is returning something like int or bool (the type, not a value of that type).
A function cannot choose which type to return at runtime; it must have a definite return type at compile time. What you can use instead is a template with a member type. You will need to use template metaprogramming for this. As an example, here is an adapter template that makes a type T into its const pointer form:
template <typename T>
struct make_const_ptr {
using type = const T*;
};
template <typename>
using make_const_ptr_t<T> = typename make_const_ptr<T>::type
This is essentially a "function" that returns a type, in the sense that you can "call" it by writing make_const_ptr_t<T>. You can do a bunch more operations on types using template metaprogramming: https://www.geeksforgeeks.org/template-metaprogramming-in-c/ .
Plus, you said in your comments that you wanted to use this to choose which template function to use on a polymorphic type. An even better way to do this is to use a virtual function; doing different things for different polymorphic types is the whole point of virtual functions:
template <typename T>
void template_function(const T& obj) {
// ...
}
class Base {
// ...
virtual void do_template_function() = 0;
};
class D : public Base {
virtual void do_template_function() {
template_function<D>(*this);
}
};
class E : public Base {
virtual void do_template_function() {
template_function<E>(*this);
}
};
void f(Base* obj) {
// ...
obj->do_template_function();
// ...
}
There is a cute library Boost.Hana that can be used for computations on types in C++ metaprogramming.
With Boost.Hana a function returning an object representing the C++ type could look like this:
auto func()
{
return hana::if_(
/*constexpr condition*/,
hana::type_c<int>,
hana::type_c<bool>
);
}

CRTP: why a difference between getting a nested type and nested method of the derived class?

The base class in the CRTP pattern can access the member functions of the derived class, but it can't access a nested type in the derived class.
Why this difference?
To illustrate, consider the following piece of code:
template<typename Derived>
struct crtp_base
{
void crtp_method() { return static_cast<Derived&>(*this).method(); } // compiles
using crtp_type = typename Derived::type; // doesn't compile
};
struct X : public crtp_base<X>
{
void method() {}
using type = int;
};
int main()
{
}
crtp_type causes a compilation error, while crtp_method compiles fine, although both attempt to access something defined in the Derived class. What is the C++ specification that explains that difference?
The difference here is that instantiation of method happens only when you actually use it while instantiation of crtp_base happens at public crtp_base<X> where type X is still incomplete. The workaround would be to use type traits:
template<typename x_Target>
struct Trait;
template<typename Derived>
struct crtp_base
{
void crtp_method() { return static_cast<Derived&>(*this).method(); }
using crtp_type = typename Trait<Derived>::type;
};
struct X;
template<>
struct Trait<X>
{
using type = int;
};
struct X : public crtp_base<X>
{
void method() {}
using type = Trait<X>::type;
};

Ignored traits specialization in c++

I have some hard time implementing traits in C++, I tried to follow several examples from the internet but it still doesn't want to compile.
I use a Term class, which contains an Attribute, an Operator and sometimes a value. For example, age < 10 or color == red are (simple) terms. Different kinds of attributes or operators exists, that inherits from classes Attribute or TermOperator.
Since a lot of methods of the term class will depend on the attribute and the operator, this is a template class. In order to simplify the manipulation of terms, I added an abstract class : AbstractTerm
class AbstractTerm {
protected:
Attribute* pAttribute;
TermOperator* pOperator;
public:
virtual bool eval(Data *) const = 0;
};
template <typename ATT, typename OP>
class Term : AbstractTerm {
typedef typename TermTraits<ATT,OP>::type VALUE_TYPE;
private:
typename TermTraits<ATT,OP>::type value;
public:
bool eval(Data *) const;
};
The value I need to store in term will depend on both attribute & operator, so I use traits to obtain the right type to store the value.
template < typename ATT, typename OP>
struct TermTraits
{
typedef int type;
};
template <>
struct TermTraits<ListAttribute, TermOperator>
{
typedef ListValue type;
};
template <>
struct TermTraits<NumericAttribute, TermOperator>
{
typedef NumericIntValue type;
};
However, in the eval method when I use VALUE_TYPE I don't get the right type
template <> bool Term<NumericAttribute, TermOperatorEquals>::eval(Data _data) const {
// VALUE_TYPE is a int, but it should be a NumericIntValue
VALUE_TYPE *pValue = data->getValue<VALUE_TYPE>(this->pAttribute->getId());
return !pValue->isEmpty && (this->value == pValue->value); // I get compilation errors here because pValue is a int* and not a 'NumericIntValue*'
};
I get the error:
error: request for member 'isEmpty' in '* pValue',
which is of non-class type 'Term<NumericAttribute,
TermOperatorExists>::VALUE_TYPE {aka int}.
I can't figure out why it doesn't use the specialisation TermTraits<NumericAttribute, TermOperator>, since TermOperatorExists inherits from TermOperator.
Traits are a new concept to me, so maybe I made some obvious mistakes. If someone has a better way or simpler way to do this I'm also interested.
Although TermOperatorExists inherits from TermOperator, those are different types, so template specialization is not called for TermOperatorExists. You need to explicitly cast TermOperatorExists to its base class in order to get specialization called.
Example:
#include <iostream>
using namespace std;
class base
{
};
class derrived: public base
{
};
class test
{
public:
template <class T> void print(T arg)
{
std::cout << "test" << std::endl;
}
};
template <>
void test::print<base>(base arg)
{
std::cout << "base specialiation" << std::endl;
};
int main()
{
cout << "Hello World" << endl;
base b;
derrived d;
test t;
t.print<int>(1);
t.print(b);
t.print(d);
t.print(static_cast<base>(d));
return 0;
}
outputs:
Hello World
test
base specialiation
test
base specialiation

How do I use the "Barton–Nackman trick" to implement trival methods?

Inspired of boost::operators I thought the Barton-Nackman idiom could be used to implement from trival member methods.
Following is what I have tried (does not compile)
template<typename T>
class impl_get_set {
typename T::storage_type get() const {
return static_cast<const T *>(this)->data_;
}
void set(typename T::storage_type d) {
*static_cast<T *>(this)->data_ = d;
}
};
struct A : public impl_get_set<A> {
typedef int storage_type;
storage_type data_;
};
struct B : public impl_get_set<B> {
typedef double storage_type;
storage_type data_;
};
As this does not compile there is clearly something I have got wrong. My question is, can this be done, and if so how?
When using CRTP, you have to take care when designing the base, i.e. impl_get_set in this case. When the derived class instantiates the base specialization, e.g. as done with A: public impl_get_set<A>, the A class is still incomplete.
However the definition of impl_get_set uses typename T::storage_type in a member function declaration. This use requires a complete T. The C++03 way to solve that is to make any associated type that the CRTP base may need part of the class template parameters:
template<typename Derived, typename StorageType>
struct get_set {
typedef StorageType storage_type;
// It's possible to define those inline as before where
// Derived will be complete in the body -- which is why
// CRTP is possible at all in the first place
storage_type get() const;
void set(storage_type s);
// Convenience for clients:
protected:
typedef get_set get_set_base;
};
struct A: get_set<A, int> {
// Member type is inherited
storage_type data;
};
template<typename T>
struct B: get_set<B<T>, double> {
// Incorrect, storage_type is dependent
// storage_type data;
// First possibility, storage_type is
// still inherited although dependent
// typename B::storage_type data;
// Second possibility, convenient if
// storage_type is used multiple times
using typename B::get_set_base::storage_type;
storage_type data;
void foo(storage_type s);
};
boost::iterator_facade is a good example of a well-written C++03-style CRTP wrapper from Boost.Iterator.
C++11 gives another way to write a CRTP base thanks in part to default template arguments for function templates. By making the derived class parameter dependent again, we can use it as if it were complete -- it will only be examined when the member function template of the CRTP base specialization is instantiated, once it is complete, and not when the CRTP base specialization itself is:
// Identity metafunction that accepts any dummy additional
// parameters
template<typename T, typename... Dependent>
struct depend_on { using type = T; };
// DependOn<T, D> is the same as using T directly, except that
// it possibly is dependent on D
template<typename t, typename... D>
using DependOn = typename depend_on<T, D...>::type;
template<typename Derived>
struct get_set {
template<
// Dummy parameter to force dependent type
typename D = void
, typename Storage = typename DependOn<Derived, D>::storage_type
>
Storage get() const
{
// Nothing to change, Derived still complete here
}
};
In fact, for your example get_set arguably doesn't need to care about whether a member type is present or not:
// std::declval is from <utility>
template<
typename D = void
, typename Self = DependOn<Derived, D>
>
auto get() const
-> decltype( std::declval<Self const&>().data )
{ return static_cast<Derived const&>(*this).data; }
This implementation of get has subtly different semantics from your own in that it returns a reference to data but that's on purpose.
The best I could figure out is that you're in a chicken/egg problem.
struct A uses impl_get_set as base, that forces instantiation. But at that point A is incomplete, its contents not yet available. Therefore T::storage_type fails to resolve to anything.
The only workaround I found was to just have another template param for impl_get_set and pass it from above. So go the opposite direction:
template<typename T, typename ST>
class impl_get_set {
public:
typedef ST storage_type;
storage_type get() const {
return static_cast<const T *>(this)->data_;
}
void set(storage_type d) {
*static_cast<T *>(this)->data_ = d;
}
};
struct A : public impl_get_set<A, int> {
storage_type data_;
};
(A is currently not used in the base, I left it in for possible other plans)

Would a static nested bool help me disable a call for certain types or is there a cleaner way?

I have a template class, say:
template<class T>
class someClient
{
void someCallbackA() {foo_->onA();}
void someCallbackB() {foo_->onB();}
private:
T* foo_;
};
which I can instantiate with a bunch of different types T which support the onA and onB interface. I happen to have a case where two out of the several different types T I use needs a particular behavior controlled from someClient so I need to add some function doBar() to these two types (call them Edge1 and Edge2). Then I want a part of the someClient code to call foo_->doBar() but without breaking when the type of foo_ does not have that. Is there a way to use boost::enable_if to have a someClient::doBar() which will call foo_->doBar() only for those two types, but not be there, or expand to nothing if the types are not Edge1 or Edge2?
I was thinking along the lines of:
template <class T, enable_if<mpl_or<is_same<T,Edge1>, is_same<T,Edge2> > >
someClient<T>::doBar() {foo_->doBar();}
You don't need to pull any special tricks at all if you just don't call member functions that don't make sense. Template member functions are only specialized when needed (unless you add an explicit specialization). So the following code works fine:
template <typename T> struct Foo
{
void do_foo() { p->foo(); }
void do_bar() { p->bar(); }
T * p;
};
struct A { void foo() {} };
int main()
{
A a;
Foo<A> x = { &a };
x.do_foo();
}
The fact that Foo<A>::do_bar wouldn't compile is not an issue, since the member function is never instantiated. And p->bar isn't a compiler error, because p has a dependent type and the line is thus only parsed in the second lookup phase (which never happens).
I think this does what you want. I used C++11 <type_traits> instead of boost's:
struct Edge {
void doBar() { std::cout << "did Bar."; }
};
template<typename T>
class someClient
{
public:
template<typename U = T>
typename
std::enable_if<std::is_same<U, Edge>::value, void>::type
doBar() { foo_->doBar(); }
template<typename U = T>
void doBar( typename std::enable_if<!std::is_same<U, Edge>::value, void>::type* = 0 )
{ /* do nothing */ }
private:
T* foo_;
};
int main()
{
someClient<int> i;
someClient<Edge> e;
i.doBar();
e.doBar(); // outputs "did Bar."
}
doBar() needs to be template itself for this to work, explanation here: std::enable_if to conditionally compile a member function