Visual Studio 2013 still doesn't support the alignas
keyword in C++11. This causes some problems with alignment of types in various situations. Thankfully the compiler will generate an error when it can't guarantee the alignment or at least give a warning.
To solve these errors and warnings I'm implementing a wrapper type that will wrap another type with some alignment restriction regardless of how the wrapper is aligned. Consider two wrapper objects A
and B
that themselves have arbitrary alignment. Let the wrapped datum be a
and b
respectively. Then A=B
will assign a=b
while still keeping a
aligned regardless of how B
was aligned because b
in itself is aligned.
I'm looking for a review on the code on the account of syntax and possible weaknesses in the design and implementation.
template< typename T, std::size_t Align = 16>
class aligned_wrapper{
public:
typedef T value_type;
template<typename... Args>
aligned_wrapper(Args&&... args){
std::size_t space = sizeof(m_storage);
auto raw_ptr = reinterpret_cast<void*>(&m_storage);
auto ptr = std::align(Align, sizeof(T), raw_ptr, space);
new (ptr)T(std::forward<Args>(args)...);
m_object = reinterpret_cast<T*>(ptr);
}
~aligned_wrapper(){
get().~T();
}
aligned_wrapper& operator = (const aligned_wrapper& that){
get() = that.get();
return *this;
}
template<typename U>
aligned_wrapper(const aligned_wrapper<U>& that)
: aligned_wrapper(that.get())
{}
template<typename U>
aligned_wrapper(aligned_wrapper<U>&& that)
: aligned_wrapper(std::move(that.get()))
{}
inline T& get(){ return *m_object; }
inline const T& get() const { return *m_object; }
void swap(aligned_wrapper& that){
using std::swap;
swap(get(), that.get());
}
friend void swap(aligned_wrapper& lhs, aligned_wrapper& rhs){
lhs.swap(rhs);
}
private:
std::aligned_storage_t<sizeof(T) + Align - 1, 1> m_storage;
T* m_object{ nullptr };
};
Although it may look a bit funky, one of the key ideas is that once the aligned_wrapper
is constructed, m_object
will never change for that instance as the address of this
will not change, this guarantees alignment. In other words, not assigning m_object
in the assignment operator is intentional.