How to emulate EBO when using raw storage? - c++

I have a component I use when implementing low-level generic types that store an object of arbitrary type (may or may not be a class type) which may be empty to take advantage of the empty base optimization:
template <typename T, unsigned Tag = 0, typename = void>
class ebo_storage {
T item;
public:
constexpr ebo_storage() = default;
template <
typename U,
typename = std::enable_if_t<
!std::is_same<ebo_storage, std::decay_t<U>>::value
>
> constexpr ebo_storage(U&& u)
noexcept(std::is_nothrow_constructible<T,U>::value) :
item(std::forward<U>(u)) {}
T& get() & noexcept { return item; }
constexpr const T& get() const& noexcept { return item; }
T&& get() && noexcept { return std::move(item); }
};
template <typename T, unsigned Tag>
class ebo_storage<
T, Tag, std::enable_if_t<std::is_class<T>::value>
> : private T {
public:
using T::T;
constexpr ebo_storage() = default;
constexpr ebo_storage(const T& t) : T(t) {}
constexpr ebo_storage(T&& t) : T(std::move(t)) {}
T& get() & noexcept { return *this; }
constexpr const T& get() const& noexcept { return *this; }
T&& get() && noexcept { return std::move(*this); }
};
template <typename T, typename U>
class compressed_pair : ebo_storage<T, 0>,
ebo_storage<U, 1> {
using first_t = ebo_storage<T, 0>;
using second_t = ebo_storage<U, 1>;
public:
T& first() { return first_t::get(); }
U& second() { return second_t::get(); }
// ...
};
template <typename, typename...> class tuple_;
template <std::size_t...Is, typename...Ts>
class tuple_<std::index_sequence<Is...>, Ts...> :
ebo_storage<Ts, Is>... {
// ...
};
template <typename...Ts>
using tuple = tuple_<std::index_sequence_for<Ts...>, Ts...>;
Lately I've been messing about with lock-free data structures and I need nodes that optionally contain a live datum. Once allocated, nodes live for the lifetime of the data structure but the contained datum is only alive while the node is active and not while the node sits in a free list. I implemented the nodes using raw storage and placement new:
template <typename T>
class raw_container {
alignas(T) unsigned char space_[sizeof(T)];
public:
T& data() noexcept {
return reinterpret_cast<T&>(space_);
}
template <typename...Args>
void construct(Args&&...args) {
::new(space_) T(std::forward<Args>(args)...);
}
void destruct() {
data().~T();
}
};
template <typename T>
struct list_node : public raw_container<T> {
std::atomic<list_node*> next_;
};
which is all fine and dandy, but wastes a pointer-sized chunk of memory per node when T is empty: one byte for raw_storage<T>::space_, and sizeof(std::atomic<list_node*>) - 1 bytes of padding for alignment. It would be nice to take advantage of EBO and allocate the unused single-byte representation of raw_container<T> atop list_node::next_.
My best attempt at creating a raw_ebo_storage performs "manual" EBO:
template <typename T, typename = void>
struct alignas(T) raw_ebo_storage_base {
unsigned char space_[sizeof(T)];
};
template <typename T>
struct alignas(T) raw_ebo_storage_base<
T, std::enable_if_t<std::is_empty<T>::value>
> {};
template <typename T>
class raw_ebo_storage : private raw_ebo_storage_base<T> {
public:
static_assert(std::is_standard_layout<raw_ebo_storage_base<T>>::value, "");
static_assert(alignof(raw_ebo_storage_base<T>) % alignof(T) == 0, "");
T& data() noexcept {
return *static_cast<T*>(static_cast<void*>(
static_cast<raw_ebo_storage_base<T>*>(this)
));
}
};
which has the desired effects:
template <typename T>
struct alignas(T) empty {};
static_assert(std::is_empty<raw_ebo_storage<empty<char>>>::value, "Good!");
static_assert(std::is_empty<raw_ebo_storage<empty<double>>>::value, "Good!");
template <typename T>
struct foo : raw_ebo_storage<empty<T>> { T c; };
static_assert(sizeof(foo<char>) == 1, "Good!");
static_assert(sizeof(foo<double>) == sizeof(double), "Good!");
but also some undesirable effects, I assume due to violation of strict aliasing (3.10/10) although the meaning of "access the stored value of an object" is debatable for an empty type:
struct bar : raw_ebo_storage<empty<char>> { empty<char> e; };
static_assert(sizeof(bar) == 2, "NOT good: bar::e and bar::raw_ebo_storage::data() "
"are distinct objects of the same type with the "
"same address.");
This solution also potential for undefined behavior upon construction. At some point the program must construct the containee object within the raw storage with placement new:
struct A : raw_ebo_storage<empty<char>> { int i; };
static_assert(sizeof(A) == sizeof(int), "");
A a;
a.value = 42;
::new(&a.get()) empty<char>{};
static_assert(sizeof(empty<char>) > 0, "");
Recall that despite being empty, a complete object necessarily has non-zero size. In other words, an empty complete object has a value representation that consists of one or more padding bytes. new constructs complete objects, so a conforming implementation could set those padding bytes to arbitrary values at construction instead of leaving memory untouched as would be the case for constructing an empty base subobject. This would of course be catastrophic if those padding bytes overlay other live objects.
So the question is, is it possible to create a standard-compliant container class that uses raw storage/delayed initialization for the contained object and takes advantage of EBO to avoid wasting memory space for the representation of the contained object?

I think you gave the answer yourself in your various observations:
You want raw memory and placement new. This requires to have at least one byte available, even if you want to construct an empty object via placement new.
You want zero bytes overhead for storing any empty objects.
These requirements are self-contradicting. The answer therefore is No, that is not possible.
You could change your requirements a bit more, though, by requiring the zero byte overhead only for empty, trivial types.
You could define a new class trait, e.g.
template <typename T>
struct constructor_and_destructor_are_empty : std::false_type
{
};
Then you specialize
template <typename T, typename = void>
class raw_container;
template <typename T>
class raw_container<
T,
std::enable_if_t<
std::is_empty<T>::value and
std::is_trivial<T>::value>>
{
public:
T& data() noexcept
{
return reinterpret_cast<T&>(*this);
}
void construct()
{
// do nothing
}
void destruct()
{
// do nothing
}
};
template <typename T>
struct list_node : public raw_container<T>
{
std::atomic<list_node*> next_;
};
Then use it like this:
using node = list_node<empty<char>>;
static_assert(sizeof(node) == sizeof(std::atomic<node*>), "Good");
Of course, you still have
struct bar : raw_container<empty<char>> { empty<char> e; };
static_assert(sizeof(bar) == 1, "Yes, two objects sharing an address");
But that is normal for EBO:
struct ebo1 : empty<char>, empty<usigned char> {};
static_assert(sizeof(ebo1) == 1, "Two object in one place");
struct ebo2 : empty<char> { char c; };
static_assert(sizeof(ebo2) == 1, "Two object in one place");
But as long as you always use construct and destruct and no placement new on &data(), you're golden.

Related

Limit variable template to a list of types

I'm trying to modernise some GStreamer code by adding smart pointers. So for instance:
GstElement *pipeline = gst_pipeline_new("test-pipeline");
gst_object_unref(pipeline);
can be rewritten:
struct GstElementDeleter {
void operator()(GstElement* p) { gst_object_unref(p); }
};
std::unique_ptr<GstElement, GstElementDeleter> pipeline = gst_pipeline_new("test-pipeline");
But gst_object_unref() can be used on any gpointer so it can be rewritten:
template<typename T>
struct GPointerDeleter {
void operator()(T* p) { gst_object_unref(p); }
};
std::unique_ptr<GstElement, GPointerDeleter<GstElement>> pipeline = gst_pipeline_new("test-pipeline");
But what I'd like to do is limit this to only handling types that can be deallocated using gst_object_unref. Is there a way of declaring a template to only work with a list of types - GstElement, GstBus, etc?
Maybe you could make template the operator() (so there is no need to explicit the template parameter defining the smart pointer) and use SFINAE to enable the operator() only for the allowed types
struct GPointerDeleter
{
template <typename T>
typename std::enable_if<std::is_same<T, GstElement>::value
|| std::is_same<T, GstBus>::value
/* or other cases */
>::type operator() (T * p) const
{ gst_object_unref(p); }
};
Or, maybe better, you can add (as suggested by Jarod42 (thanks)) a static_assert() check inside the operator()
struct GPointerDeleter
{
template <typename T>
void operator() (T * p) const
{
static_assert( std::is_same<T, GstElement>::value
|| std::is_same<T, GstBus>::value
/* or other cases */, "some error message" );
gst_object_unref(p);
}
};
Perhaps a type trait? See <type_traits> if you haven't seen these before.
template<typename T>
struct can_gst_unref : std::false_type { };
// for each type...
template<> struct can_gst_unref<GstElement> : std::true_type { };
// convenient alias, as is convention for type traits
template<typename T>
inline constexpr bool can_gst_unref_v = can_gst_unref<T>::value;
// now conditionally define operator() in your deleter
struct GstDeleter {
template<typename T>
std::enable_if_t<can_gst_unref_v<T>> operator()(T* p) { gst_object_unref(p); }
};
// Making the function a template instead of the class reduces clutter at usage
std::unique_ptr<GstElement, GstDeleter> works(gst_pipeline_new("test-pipeline"));
// can_gst_unref is not specialized to std::string
// so the general case takes over, and gives can_gst_unref_v<std::string> = false
// std::enable_if_t thus doesn't produce a type, and operator() is not defined, because it has no return type
// therefore, this doesn't compile
std::unique_ptr<std::string, GstDeleter> whoops;

How to check if union contains type (using type_traits)?

I have a function template like the following:
template<class U, class T>
T* unsafeCast(U* theUnion) {
reinterpret_cast<T*>(theUnion);
}
How can I make sure this only compiles if T is a type contained within the union U, so that the following holds?
union FooUnion {
int a;
double b;
} foo;
unsafeCast<FooUnion, int>(&foo); // compiles
unsafeCast<FooUnion, double>(&foo); // compiles
unsafeCast<FooUnion, char>(&foo); // does not compile
I understand that is_union from <type_traits> allows to check for a union, but how can I check for types within a union?
You cannot.
boost::variant and std::variant are solutions to this problem such that the union carries with it the type information you need.
You could create a raw union like this:
template<class T>
struct data_holder {
T data;
};
template<class...Ts>
struct union_data;
template<>
struct union_data<>{};
template<class T0>
struct union_data<T0>:data_holder<T0> {};
template<class T0, class...Ts>
struct union_data<T0, Ts...> {
union {
union_data<T0> lhs;
union_data<Ts...> rhs;
};
};
template<class...Ts>
struct raw_union:union_data<Ts...>{
template<class T>
constexpr static bool valid_type() {
return (std::is_same<T, Ts>{}||...); // rewrite in C++14/11
}
template<class T>
union_data<T>* get_data_ptr() {
static_assert( valid_type<T>() );
return reinterpret_cast<union_data<T>*>(this);
}
template<class T>
union_data<T> const* get_data_ptr() const{
static_assert( valid_type<T>() );
return reinterpret_cast<union_data<T> const*>(this);
}
template<class T>
T& get_unsafe() {
return get_data_ptr<T>()->data;
}
template<class T>
T const& get_unsafe() const {
return get_data_ptr<T>()->data;
}
template<class T, class...Us>
T& emplace( Us&&... us ) {
auto* ptr = ::new( (void*)get_data_ptr<T>() ) union_data<T>{ T(std::forward<Us>(us)...) };
return ptr->data;
}
template<class T>
void dtor() {
get_data_ptr<T>()->~T();
}
};
which is unsafe and undiscriminated, but does check if foo.get_unsafe<int>() actually contains an int.
live example.
Use:
raw_union<int, double> un;
un.emplace<int>(7);
std::cout << un.get_unsafe<int>() << "\n";
it does not support multiple union members of the same type. You are in charge of calling .emplace<T>(x) before using T, and if a non-trivial destructor .dtor<T>().
Accessing members that are not active is just as perilous as doing so with raw C/C++ unions.
If you can add constructors to your unions you can do it like this:
#include <type_traits>
// Use std::void_t to only allow types that the union can be constructed from
template<class T, class U, class = std::void_t<decltype(U{std::declval<T>()})>>
T* unsafeCast(U* theUnion) {
return reinterpret_cast<T*>(theUnion);
}
union FooUnion {
int a;
double b;
// Explictly add constructors for each desired type
FooUnion(int a) : a{a} {}
FooUnion(double b) : b{b} {}
// Add a deleted catch all to prevent implicit conversions, e.g. from char
template <class T>
FooUnion(T) = delete;
} foo(0);
int main() {
unsafeCast<int>(&foo); // compiles
unsafeCast<double>(&foo); // compiles
unsafeCast<char>(&foo); // does not compile
}
Godbolt

Type Erasure for objects containing a std::tuple in c++11

Lets say I have a generic class Container that contains any type of tuple, and has a function template<typename T> T& get<T>(); that returns a reference to the element in the tuple. My very simple implementation looks like this:
template<typename... Ts>
class Container
{
std::tuple<Ts...> contents;
public:
Container(const Ts&... ts) : contents(ts...) {}
template <typename T>
T& get()
{
//TypeIndex is some meta-programming struct to find index of T in Ts
return std::get<TypeIndex<T, Ts...>::value>(contents);
}
};
Are there any good type erasure techniques to turn Container into a regular class without altering the get function signature? As in calling get<T>() without knowing the tuples full type list? Something like this:
Struct A { int x; }
Struct B { int y; }
Struct C { int z; }
int main()
{
Container container(A(), B()); //Underlying storage is a std::tuple<A, B>
A& a = container.get<A>(); //Doesn't know the tuples type list but assumes A is in there.
C& c = container.get<C>(); //C isn't in the tuples type list, crash program, which would be correct behavior.
}
boost::any is the usual go-to solution for these types of problems, but doesn't solve this particular problem because I would have to know the actual type of the underlying tuple to cast. Like if I tried to use it in the example above I would do boost::any_cast<std::tuple<A, B>> to get A, or B which isn't any use to me because I'm purposely trying to hide the tuple type list.
Edit: full definition of TypeIndex.
#include <type_traits>
template <typename T, typename... Ts>
struct TypeIndex;
template <typename T, typename... Ts>
struct TypeIndex<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename U, typename... Ts>
struct TypeIndex<T, U, Ts...> : std::integral_constant<std::size_t, 1 + TypeIndex<T, Ts...>::value> {};
Instead of hand written TypeIndex<T, Ts...>::value you can use typeid(T)::hash_code() and store data in a std::unordered_map<size_t, boost::any>.
std::tuple does not store information about underlying types. That information is encoded in tuple's type. So if your get method can't know the type of the tuple, then it can't get offset in it where the value is stored. So you have to revert to dynamic methods and having a map is the simpliest one.
A slightly more efficient solution than the ones proposed so far is to use std::tuple as the actual underlying storage, thus avoiding use of any or unordered_map
If we use the classic type-erasure pattern, we only need one dynamic allocation (plus whatever is required to copy the actual objects), or zero if you implement small buffer optimization.
We start by defining a base interface to access an element by type.
struct base
{
virtual ~base() {}
virtual void * get( std::type_info const & ) = 0;
};
We use void* instead of any to return a reference to the object, thus avoiding a copy and possibly a memory allocation.
The actual storage class is derived from base, and templated on the arguments it can contain:
template<class ... Ts>
struct impl : base
{
template<class ... Us>
impl(Us && ... us) : data_(std::forward<Us>(us) ... )
{
//Maybe check for duplicated types and throw.
}
virtual void * get( std::type_info const & ti )
{
return get_helper( ti, std::index_sequence_for<Ts...>() );
}
template<std::size_t ... Indices>
void* get_helper( std::type_info const & ti, std::index_sequence<Indices...> )
{
//If you know that only one element of a certain type is available, you can refactor this to avoid comparing all the type_infos
const bool valid[] = { (ti == typeid(Ts)) ... };
const std::size_t c = std::count( std::begin(valid), std::end(valid), true );
if ( c != 1 )
{
throw std::runtime_error(""); // something here
}
// Pack the addresses of all the elements in an array
void * result[] = { static_cast<void*>(& std::get<Indices>(data_) ) ... };
// Get the index of the element we want
const int which = std::find( std::begin(valid), std::end(valid), true ) - std::begin(valid);
return result[which];
}
std::tuple<Ts ... > data_;
};
Now we only have to wrap this in a type-safe wrapper:
class any_tuple
{
public:
any_tuple() = default; // allow empty state
template<class ... Us>
any_tuple(Us && ... us) :
m_( new impl< std::remove_reference_t< std::remove_cv_t<Us> > ... >( std::forward<Us>(us) ... ) )
{}
template<class T>
T& get()
{
if ( !m_ )
{
throw std::runtime_error(""); // something
}
return *reinterpret_cast<T*>( m_->get( typeid(T) ) );
}
template<class T>
const T& get() const
{
return const_cast<any_tuple&>(*this).get<T>();
}
bool valid() const { return bool(m_); }
private:
std::unique_ptr< base > m_; //Possibly use small buffer optimization
};
Check it live.
This can be extended further in many ways, for instance you can add a constructor that takes an actual tuple, you can access by index and pack the value in a std::any, etc.
#include <iostream>
struct tuple_base {
virtual ~tuple_base() {}
};
template <typename T>
struct leaf : virtual tuple_base {
leaf(T const & t) : value(t) {}
virtual ~leaf() {}
T value;
};
template <typename ... T>
struct tuple : public leaf<T> ... {
template <typename ... U>
tuple(U && ... u) : leaf<T>{static_cast<U&&>(u)} ... {}
};
struct container {
tuple_base* erased_value;
template <typename T>
T & get() {
return dynamic_cast<leaf<T>*>(erased_value)->value;
}
};
int main() {
container c{new tuple<int, float, char>{1, 1.23f, 'c'}};
std::cout << c.get<float>() << std::endl;
}
The key is that you must know more information about the structure of the tuple type. It is not possible to extract information from a type erased arbitrary tuple implementation using only a single type which it contains. This is more of a proof of concept, and you would probably be better off using something else, though it is the solution to what you asked.
If you're ok with using boost::any, you could use a vector or unordered_map of them. Here's a version implemented with unordered_map:
class Container
{
public:
template<typename... Ts>
Container(std::tuple<Ts...>&& t)
{
tuple_assign(std::move(t), data, std::index_sequence_for<Ts...>{});
}
template<typename T>
T get()
{
auto it = data.find(typeid(T));
if(it == data.cend()) {
throw boost::bad_any_cast{};
} else {
return boost::any_cast<T>(it->second);
}
}
private:
std::unordered_map<std::type_index, boost::any> data;
};
And then you could write almost as in your request. I changed the constructor to accept a tuple to avoid a host of sfinae code to prevent overridding copy/move constructors, but you can do this if you so wish.
Container c(std::make_tuple(1, 1.5, A{42}));
try {
std::cout << "int: " << c.get<int>() << '\n';
std::cout << "double: " << c.get<double>() << '\n';
std::cout << "A: " << c.get<A>().val << '\n';
c.get<A&>().val = 0;
std::cout << "A: " << c.get<A>().val << '\n';
std::cout << "B: " << c.get<B>().val << '\n'; // error
} catch (boost::bad_any_cast const& ex) {
std::cout << "exception: " << ex.what() << '\n';
}
live demo
You could also instruct your Container to commit std::terminate() instead of throwing an exception.

static size array of different struct's

I have an application that consists of multiple tasks that share common data using shared memory. Up to now the data in shared memory look like that:
struct Store = {
int id;
Array<Module, 5> modules;
};
where Module is defined as
struct Module = {
uint32_t a;
char b[64];
Array<Component, 10> components;
};
This Store structure has a fixed size an can be easily used within shared memory.
But now I have to support other Modules, lets say ModuleA and ModuleB. Within the normal C++ context I would model these as:
struct ModuleBase {
// common informations
};
struct ModuleA : public ModuleBase {
// ...
};
struct ModuleB : public ModuleBase {
// ...
};
and replace Module by Module* in the Store.
But within the shared memory this is not so easy.
Accessing data in shared memory is easy for fix structures that's why a compile time array is used. I would like to have this property with my different module's.
Idea 1
union Module {
ModuleType type;
ModuleA moduleA;
ModuleB moduleB;
};
The problem is that my Module classes have constructors and that is not allowed inside the union. Access is easy using the type and then Module.moduleX
fix: remove need of constructors
Idea 2
Using a template that evaluates the maximum size of given classes, e.g.
const size_t max_module_size = MaxTMP<ModuleA, ModuleB>::value;
This is the size of the buffer I need to store the modules:
char ModuleBuffer[max_module_size];
(maybe the ModuleBuffer has to be encapsulated in a struct, for usage with Array)
Access is tricky, the content of ModuleBuffer has to be casted to ModuleBase and according to the type to ModuleX. That for I think I need some reinterpret_cast. And I also need to cast the 'ModuleX' in some way to put into the ModuleBuffer.
Question
I don't like both ideas but I cannot imagine another way to handle this problem. Do you have any comments or - even better - solutions?
Effectively, you are between a rock and a hard place.
I would give a try to boost::variant, because of the facilities it comes with, otherwise it's not too difficult to recreate a similar thing, but it is long...
On top of size, you also need to take care about alignment. It will help to use C++11 here, although it is possible to write this in C++03 with a couple libraries/extensions.
Note that a union is not anything so special, and you can easily implement your own, in a way, and like boost::variant make it "tagged".
A couple helpers will help nicely:
/// Size and Alignment utilties
constexpr size_t max(size_t t) { return t; }
template <typename... U>
constexpr size_t max(size_t l, size_t r, U... tail) {
return l > max(r, tail...) ? l : max(r, tail...);
}
template <typename... T>
struct size { static size_t const value = max(sizeof(T)...); };
template <typename... T>
struct alignment { static size_t const value = max(alignof(T)...); };
/// Position of a type in the list
template <typename...> struct position;
template <typename T>
struct position<T> {
static size_t const value = 0;
};
template <typename T, typename Head, typename... Tail>
struct position<T, Head, Tail...> {
static size_t const value =
std::is_same<T, Head>::value ? 0 : 1 + position<T, Tail...>::value;
};
/// Type at a given position
template <size_t, typename...> struct at;
template <size_t N, typename T, typename... Tail>
struct at<N, T, Tail...> { typedef typename at<N-1, Tail..>::type type; };
template <typename T, typename... Tail>
struct at<0, T, Tail...> { typedef T type; };
Now the true fun starts: how to apply a function in a typesafe manner with a type that may change at runtime :x ?
/// Function application
template <typename...> struct Apply;
template <typename H, typename... Tail>
struct Apply<H, Tail...> {
// Mutable
template <typename Func>
static void Do(Func& f, void* storage, size_t tag) {
if (tag == 0) { f(*reinterpret_cast<H*>(storage)); }
else { Apply<Tail...>::Do(f, storage, tag-1); }
}
template <typename Func>
static void Do(Func const& f, void* storage, size_t tag) {
if (tag == 0) { f(*reinterpret_cast<H*>(storage)); }
else { Apply<Tail...>::Do(f, storage, tag-1); }
}
// Const
template <typename Func>
static void Do(Func& f, void const* storage, size_t tag) {
if (tag == 0) { f(*reinterpret_cast<H const*>(storage)); }
else { Apply<Tail...>::Do(f, storage, tag-1); }
}
template <typename Func>
static void Do(Func const& f, void const* storage, size_t tag) {
if (tag == 0) { f(*reinterpret_cast<H const*>(storage)); }
else { Apply<Tail...>::Do(f, storage, tag-1); }
}
}; // struct Apply
/// We need recursion to end quietly even though `tag` is a runtime argument
/// we place the precondition that `tag` should be a valid index in the type
/// list so this should never be reached.
template <>
struct Apply<> {
template <typename... T>
static void Do(T...&&) { abort(); }
}; // struct Apply
Now we can use this to dynamically dispatch in a type safe manner.
/// Variant itself
template <typename... List>
class Variant {
public:
/// Constructor & co
Variant() {
typedef typename at<0, List...>::type First;
new (&_storage) First();
}
Variant(Variant const& other) {
this->initialize(other);
}
Variant& operator=(Variant const& other) {
this->destroy();
this->initialize(other);
return *this;
}
~Variant() { this->destroy(); }
/// Conversions
template <typename T>
explicit Variant(T const& t) {
_tag = position<T, List...>::value;
new (&_storage) T(t);
}
template <typename T>
Variant& operator=(T const& t) {
_tag = position<T, List...>::value;
this->destroy();
new (&_storage) T(t);
return *this;
}
/// Applying a func
template <typename Func>
void apply(Func& f) { Apply<List...>::Do(f, &_storage, _tag); }
template <typename Func>
void apply(Func& f) const { Apply<List...>::Do(f, &_storage, _tag); }
template <typename Func>
void apply(Func const& f) { Apply<List...>::Do(f, &_storage, _tag); }
template <typename Func>
void apply(Func const& f) const { Apply<List...>::Do(f, &_storage, _tag); }
private:
void initialize(Variant const& v) {
struct {
template <typename T>
void operator()(T& t) const { new (_storage) T(t); }
void* _storage;
} copier = { &_storage };
v.apply(copier);
_tag = v._tag;
}
void destroy() {
struct {
template <typename T>
void operator()(T& t) const { t.~T(); }
} eraser;
this->apply(eraser);
}
std::aligned_storage<size<List...>::value,
alignment<List...>::value> _storage;
size_t _tag;
}; // class Variant
Did I say easy ?
Well, there is a subtle issue still: the operator= implementations are not exception safe. In your case it should not be an issue, since you do not have dynamic memory allocation in those types.
References:
std::aligned_storage

Detecting a function in C++ at compile time

Is there a way, presumably using templates, macros or a combination of the two, that I can generically apply a function to different classes of objects but have them respond in different ways if they do not have a specific function?
I specifically want to apply a function which will output the size of the object (i.e. the number of objects in a collection) if the object has that function but will output a simple replacement (such as "N/A") if the object doesn't. I.e.
NO_OF_ELEMENTS( mySTLMap ) -----> [ calls mySTLMap.size() to give ] ------> 10
NO_OF_ELEMENTS( myNoSizeObj ) --> [ applies compile time logic to give ] -> "N/A"
I expect that this might be something similar to a static assertion although I'd clearly want to compile a different code path rather than fail at build stage.
From what I understand, you want to have a generic test to see if a class has a certain member function. This can be accomplished in C++ using SFINAE. In C++11 it's pretty simple, since you can use decltype:
template <typename T>
struct has_size {
private:
template <typename U>
static decltype(std::declval<U>().size(), void(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) type;
enum { value = type::value };
};
If you use C++03 it is a bit harder due to the lack of decltype, so you have to abuse sizeof instead:
template <typename T>
struct has_size {
private:
struct yes { int x; };
struct no {yes x[4]; };
template <typename U>
static typename boost::enable_if_c<sizeof(static_cast<U*>(0)->size(), void(), int()) == sizeof(int), yes>::type test(int);
template <typename>
static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
Of course this uses Boost.Enable_If, which might be an unwanted (and unnecessary) dependency. However writing enable_if yourself is dead simple:
template<bool Cond, typename T> enable_if;
template<typename T> enable_if<true, T> { typedef T type; };
In both cases the method signature test<U>(int) is only visible, if U has a size method, since otherwise evaluating either the decltype or the sizeof (depending on which version you use) will fail, which will then remove the method from consideration (due to SFINAE. The lengthy expressions std::declval<U>().size(), void(), std::true_type() is an abuse of C++ comma operator, which will return the last expression from the comma-separated list, so this makes sure the type is known as std::true_type for the C++11 variant (and the sizeof evaluates int for the C++03 variant). The void() in the middle is only there to make sure there are no strange overloads of the comma operator interfering with the evaluation.
Of course this will return true if T has a size method which is callable without arguments, but gives no guarantees about the return value. I assume wou probably want to detect only those methods which don't return void. This can be easily accomplished with a slight modification of the test(int) method:
// C++11
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
//C++03
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);
There was a discussion about the abilities of constexpr some times ago. It's time to use it I think :)
It is easy to design a trait with constexpr and decltype:
template <typename T>
constexpr decltype(std::declval<T>().size(), true) has_size(int) { return true; }
template <typename T>
constexpr bool has_size(...) { return false; }
So easy in fact that the trait loses most of its value:
#include <iostream>
#include <vector>
template <typename T>
auto print_size(T const& t) -> decltype(t.size(), void()) {
std::cout << t.size() << "\n";
}
void print_size(...) { std::cout << "N/A\n"; }
int main() {
print_size(std::vector<int>{1, 2, 3});
print_size(1);
}
In action:
3
N/A
This can be done using a technique called SFINAE. In your specific case you could implement that using Boost.Concept Check. You'd have to write your own concept for checking for a size-method. Alternatively you could use an existing concept such as Container, which, among others, requires a size-method.
You can do something like
template< typename T>
int getSize(const T& t)
{
return -1;
}
template< typename T>
int getSize( const std::vector<T>& t)
{
return t.size();
}
template< typename T , typename U>
int getSize( const std::map<T,U>& t)
{
return t.size();
}
//Implement this interface for
//other objects
class ISupportsGetSize
{
public:
virtual int size() const= 0;
};
int getSize( const ISupportsGetSize & t )
{
return t.size();
}
int main()
{
int s = getSize( 4 );
std::vector<int> v;
s = getSize( v );
return 0;
}
basically the most generic implementation is always return -1 or "NA" but for vector and maps it will return the size. As the most general one always matches there is never a build time failure
Here you go. Replace std::cout with the output of your liking.
template <typename T>
class has_size
{
template <typename C> static char test( typeof(&C::size) ) ;
template <typename C> static long test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
template<bool T>
struct outputter
{
template< typename C >
static void output( const C& object )
{
std::cout << object.size();
}
};
template<>
struct outputter<false>
{
template< typename C >
static void output( const C& )
{
std::cout << "N/A";
}
};
template<typename T>
void NO_OF_ELEMENTS( const T &object )
{
outputter< has_size<T>::value >::output( object );
}
You could try something like:
#include <iostream>
#include <vector>
template<typename T>
struct has_size
{
typedef char one;
typedef struct { char a[2]; } two;
template<typename Sig>
struct select
{
};
template<typename U>
static one check (U*, select<char (&)[((&U::size)!=0)]>* const = 0);
static two check (...);
static bool const value = sizeof (one) == sizeof (check (static_cast<T*> (0)));
};
struct A{ };
int main ( )
{
std::cout << has_size<int>::value << "\n";
std::cout << has_size<A>::value << "\n";
std::cout << has_size<std::vector<int>>::value << "\n";
}
but you have to be careful, this does neither work when size is overloaded, nor when it is a template. When you can use C++11, you can replace the above sizeof trick by decltype magic