I'm writing a client for a system that returns values of natural types in random order (some can be int, others float, others string [well, almost natural]). The problem is, I don't know what type a value will be at compile time.
Since I don't know the type of the value to be returned until after the remote system has been queried, what is the best way to provide a uniform interface that allows a user of the client library to extract the value in the right type?
If querying the remote system once returns a string, I'd like my get_value() to return a string. If an int, make it return an int. Alternatively, how to have the client library call the getter with the right type?
I guess templates with type hinting would be a good way to achieve this?
Examine boost or std variant if there is a finite list of supported types.
If not a finite list, boost or std any (or a variant containing an any).
You can find other implementations as well. The std versions are in C++17.
A simplified version of variant could probably be written in a 100 or two lines of code.
Here is a crude C++14 variant:
constexpr std::size_t max() { return 0; }
template<class...Ts>
constexpr std::size_t max( std::size_t t0, Ts...ts ) {
return (t0<max(ts...))?max(ts...):t0;
}
template<class T0, class...Ts>
struct index_of_in;
template<class T0, class...Ts>
struct index_of_in<T0, T0, Ts...>:std::integral_constant<std::size_t, 0> {};
template<class T0, class T1, class...Ts>
struct index_of_in<T0, T1, Ts...>:
std::integral_constant<std::size_t,
index_of_in<T0, Ts...>::value+1
>
{};
struct variant_vtable {
void(*dtor)(void*) = 0;
void(*copy)(void*, void const*) = 0;
void(*move)(void*, void*) = 0;
};
template<class T>
void populate_vtable( variant_vtable* vtable ) {
vtable->dtor = [](void* ptr){ static_cast<T*>(ptr)->~T(); };
vtable->copy = [](void* dest, void const* src){
::new(dest) T(*static_cast<T const*>(src));
};
vtable->move = [](void* dest, void* src){
::new(dest) T(std::move(*static_cast<T*>(src)));
};
}
template<class T>
variant_vtable make_vtable() {
variant_vtable r;
populate_vtable<T>(&r);
return r;
}
template<class T>
variant_vtable const* get_vtable() {
static const variant_vtable table = make_vtable<T>();
return &table;
}
template<class T0, class...Ts>
struct my_variant {
std::size_t index = -1;
variant_vtable const* vtable = 0;
static constexpr auto data_size = max(sizeof(T0),sizeof(Ts)...);
static constexpr auto data_align = max(alignof(T0),alignof(Ts)...);
template<class T>
static constexpr std::size_t index_of() {
return index_of_in<T, T0, Ts...>::value;
}
typename std::aligned_storage< data_size, data_align >::type data;
template<class T>
T* get() {
if (index_of<T>() == index)
return static_cast<T*>((void*)&data);
else
return nullptr;
}
template<class T>
T const* get() const {
return const_cast<my_variant*>(this)->get<T>();
}
template<class F, class R>
using applicator = R(*)(F&&, my_variant*);
template<class T, class F, class R>
static applicator<F, R> get_applicator() {
return [](F&& f, my_variant* ptr)->R {
return std::forward<F>(f)( *ptr->get<T>() );
};
}
template<class F, class R=typename std::result_of<F(T0&)>::type>
R visit( F&& f ) & {
if (index == (std::size_t)-1) throw std::invalid_argument("variant");
static const applicator<F, R> table[] = {
get_applicator<T0, F, R>(),
get_applicator<Ts, F, R>()...
};
return table[index]( std::forward<F>(f), this );
}
template<class F,
class R=typename std::result_of<F(T0 const&)>::type
>
R visit( F&& f ) const& {
return const_cast<my_variant*>(this)->visit(
[&f](auto const& v)->R
{
return std::forward<F>(f)(v);
}
);
}
template<class F,
class R=typename std::result_of<F(T0&&)>::type
>
R visit( F&& f ) && {
return visit( [&f](auto& v)->R {
return std::forward<F>(f)(std::move(v));
} );
}
explicit operator bool() const { return vtable; }
template<class T, class...Args>
void emplace( Args&&...args ) {
clear();
::new( (void*)&data ) T(std::forward<Args>(args)...);
index = index_of<T>();
vtable = get_vtable<T>();
}
void clear() {
if (!vtable) return;
vtable->dtor( &data );
index = -1;
vtable = nullptr;
}
~my_variant() { clear(); }
my_variant() {}
void copy_from( my_variant const& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->copy( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
void move_from( my_variant&& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->move( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
my_variant( my_variant const& o ) {
copy_from(o);
}
my_variant( my_variant && o ) {
move_from(std::move(o));
}
my_variant& operator=(my_variant const& o) {
copy_from(o);
return *this;
}
my_variant& operator=(my_variant&& o) {
move_from(std::move(o));
return *this;
}
template<class T,
typename std::enable_if<!std::is_same<typename std::decay<T>::type, my_variant>{}, int>::type =0
>
my_variant( T&& t ) {
emplace<typename std::decay<T>::type>(std::forward<T>(t));
}
};
Live example.
Converting to C++11 will consist of a bunch of replacing lambdas with helpers. I don't like writing in C++11, and this C++14 is a mostly mechanical transformations away from it.
It is crude, in that visit takes exactly one variant and returns void, among other reasons.
Code is almost completely untested, but the design is sound.
There are two different use case. If the client program can know in advance the type of the value it wants, you can either use a different getter for each possible type (the good old C way with for example getInt, getDouble, getString), or use templated getters (modern C++ way):
template <class T>
T get(char *byte_array) {
T value;
# manage to extract the value
return T;
}
and explictely instanciate them to make sure that they will be available.
In the client library, the usage will be:
int i = get<int>(byte_array);
If the client program may received data in an order which is unknow at compile time, you must find a way to return a variant data type (old Basic programmers remember that). You can find implementations in boost or C++ 17, but a trivial implementation could be:
struct variant {
enum Type { INT, DOUBLE, STRING, ... } type;
union {
int int_val;
double d_val;
std::string str_val;
...
};
};
In that case the client program will use
variant v = get(byte_array);
switch v.type {
case INT:
...
}
I had this exact same problem with the HDF5 library. The type of a dataset from a file can be any native type (ignoring structs for now). My solution was the following:
Create an abstract base class
Create a template class that derives from the abstract class, where the type is the runtime type you need
Create static methods in the base class that will read the type from your system, and then decide what to instantiate.
For example:
static std::shared_ptr<Base> GetVariable()
{
switch(mytype)
{
case INT16:
return std::make_shared<Derived<uint16_t>>(value);
case INT32:
return std::make_shared<Derived<uint32_t>>(value);
//etc...
}
}
There are many advantages of this, including that you could make a base-class method that gets the string value for all your types, and use the cool std::to_string for all types. You'll only need specializations if you need to do something that is type specific.
You said you were working in C++11 so if you don't want to use Boost for it's Variant type then you can use a standard C-Style union if the return type is a limited set of types.
If you want a variable, unrestricted, return type then you will probably want to look into 'Concept Based Polymorphism' or 'Type Erasure' design patters.
It's also worth looking into 'Template Specialisation', it won't be any use unless you know the return type when calling but it's a good trick to get specific type handlers with the same signature.
Related
At work, I ran into a situation where the best type to describe the result returned from a function would be std::variant<uint64_t, uint64_t> - of course, this isn't valid C++, because you can't have two variants of the same type. I could represent this as a std::pair<bool, uint64_t>, or where the first element of the pair is an enum, but this is a special case; a std::variant<uint64_t, uint64_t, bool> isn't so neatly representable, and my functional programming background really made me want Either - so I went to try to implement it, using the Visitor pattern as I have been able to do in other languages without native support for sum types:
template <typename A, typename B, typename C>
class EitherVisitor {
virtual C onLeft(const A& left) = 0;
virtual C onRight(const B& right) = 0;
};
template <typename A, typename B>
class Either {
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) = 0;
};
template <typename A, typename B>
class Left: Either<A, B> {
private:
A value;
public:
Left(const A& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onLeft(value);
}
};
template <typename A, typename B>
class Right: Either<A, B> {
private:
B value;
public:
Right(const B& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onRight(value);
}
};
C++ rejects this, because the template method Accept cannot be virtual. Is there a workaround to this limitation, that would allow me to correctly represent the fundamental sum type in terms of its f-algebra and catamorphism?
Perhaps the simplest solution is a lightweight wrapper around T for Right and Left?
Basically a strong type alias (could also use Boost's strong typedef)
template<class T>
struct Left
{
T val;
};
template<class T>
struct Right
{
T val;
};
And then we can distinguish between them for visitation:
template<class T, class U>
using Either = std::variant<Left<T>, Right<U>>;
Either<int, int> TrySomething()
{
if (rand() % 2 == 0) // get off my case about rand(), I know it's bad
return Left<int>{0};
else
return Right<int>{0};
}
struct visitor
{
template<class T>
void operator()(const Left<T>& val_wrapper)
{
std::cout << "Success! Value is: " << val_wrapper.val << std::endl;
}
template<class T>
void operator()(const Right<T>& val_wrapper)
{
std::cout << "Failure! Value is: " << val_wrapper.val << std::endl;
}
};
int main()
{
visitor v;
for (size_t i = 0; i < 10; ++i)
{
auto res = TrySomething();
std::visit(v, res);
}
}
Demo
std::variant<X,X> is valid C++.
It is a bit awkward to use, because std::visit doesn't give you the index, and std::get<X> won't work either.
The way you can work around this is to create a variant-of-indexes, which is like a strong enum.
template<std::size_t i>
using index_t = std::integral_constant<std::size_t, i>;
template<std::size_t i>
constexpr index_t<i> index = {};
template<std::size_t...Is>
using number = std::variant< index_t<Is>... >;
namespace helpers {
template<class X>
struct number_helper;
template<std::size_t...Is>
struct number_helper<std::index_sequence<Is...>> {
using type=number<Is...>;
};
}
template<std::size_t N>
using alternative = typename helpers::number_helper<std::make_index_sequence<N>>::type;
we can then extract the alternative from a variant:
namespace helpers {
template<class...Ts, std::size_t...Is, class R=alternative<sizeof...(Ts)>>
constexpr R get_alternative( std::variant<Ts...> const& v, std::index_sequence<Is...> ) {
constexpr R retvals[] = {
R(index<Is>)...
};
return retvals[v.index()];
}
}
template<class...Ts>
constexpr alternative<sizeof...(Ts)> get_alternative( std::variant<Ts...> const& v )
{
return helpers::get_alternative(v, std::make_index_sequence<sizeof...(Ts)>{});
}
so now you have a std::variant<int, int>, you can
auto which = get_alternative( var );
and which is a variant, represented at runtime by an integer which is the index of the active type in var. You can:
std::variant<int, int> var( std::in_place_index_t<1>{}, 7 );
auto which = get_alternative( var );
std::visit( [&var](auto I) {
std::cout << std::get<I>(var) << "\n";
}, get_alternative(var) );
and get access to which of the alternative possibilities in var is active with a compile time constant.
The get_alternative(variant), I find, makes variant<X,X,X> much more usable, and fills in the hole I think you might be running into.
Live example.
Now if you don't need a compile-time index of which one is active, you can just call var.index(), and visit via visit( lambda, var ).
When you construct the variant, you do need the compile time index to do a variant<int, int> var( std::in_place_index_t<0>{}, 7 ). The wording is a bit awkward, because while C++ supports variants of multiples of the same type, it considers them a bit less likely than a "standard" disjoint variant outside of generic code.
But I've used this alternative and get_alternative like code to support functional programming like data glue code before.
I am trying to obtain a subset of the variadic arguments of current class wrapper to instantiate a new one
Currently I have this:
// Reference: https://stackoverflow.com/questions/27941661/generating-one-class-member-per-variadic-template-argument
// Template specialization
template<typename T, typename... Next> class VariadicClass;
// Base case extension
template <typename T>
class VariadicClass<T> {
private:
T value_;
protected:
void SetField(T & value) {
value_ = value;
}
T & GetField() {
return value_;
}
};
// Inductive case
template <typename T, typename ... Next>
class VariadicClass : public VariadicClass<T>, public VariadicClass<Next...> {
public:
// Copy the values into the variadic class
template <typename F>
void Set(F f) {
this->VariadicClass<F>::SetField(f);
}
// Retrieve by reference
template <typename F>
F & Get() {
return this->VariadicClass<F>::GetField();
}
};
And what I want to achieve is something along the following:
[C]: A subset of Args...
VariadicClass<[C]> * Filter(VariadicClass<Args...> input) {
return new VariadicClass<[C]>(GetSubsetFrom(input, [C]));
}
VariadicClass<int, bool, char> class1;
VariadicClass<int, bool> * variadic = Filter(class1);
You can assume that each type is only once in the variadic class and that I will always ask for a subset of the current variadic types. I don't know if this is currently possible in C++ 11?
Thank you for your help.
It seems to me that you're trying to reinvent the wheel (where "wheel", in this case, is std::tuple).
Anyway, what you ask seems simple to me
template <typename ... As1, typename ... As2>
VariadicClass<As1...> * Filter(VariadicClass<As2...> in)
{
using unused = int[];
auto ret = new VariadicClass<As1...>();
(void)unused { 0, (ret->template Set<As1>(in.template Get<As1>()), 0)... };
return ret;
}
The problem I see is that the As1... types (the types of the returned VariadicClass) aren't deducible by the returned value, so you can't write
VariadicClass<int, bool> * variadic = Filter(class1);
You have to explicit the As1... types calling Filter(), so
VariadicClass<int, bool> * variadic = Filter<int, bool>(class1);
or, maybe better,
auto variadic = Filter<int, bool>(class1);
The following is a full compiling example
#include <iostream>
template <typename, typename...>
class VariadicClass;
template <typename T>
class VariadicClass<T>
{
private:
T value_;
protected:
void SetField (T & value)
{ value_ = value; }
T & GetField ()
{ return value_; }
};
template <typename T, typename ... Next>
class VariadicClass : public VariadicClass<T>, public VariadicClass<Next...>
{
public:
template <typename F>
void Set (F f)
{ this->VariadicClass<F>::SetField(f); }
template <typename F>
F & Get()
{ return this->VariadicClass<F>::GetField(); }
};
template <typename ... As1, typename ... As2>
VariadicClass<As1...> * Filter(VariadicClass<As2...> in)
{
using unused = int[];
auto ret = new VariadicClass<As1...>();
(void)unused { 0, (ret->template Set<As1>(in.template Get<As1>()), 0)... };
return ret;
}
int main()
{
VariadicClass<int, bool, char> c1;
c1.Set<int>(42);
c1.Set<bool>(true);
c1.Set<char>('Z');
auto pC2 = Filter<int, bool>(c1);
std::cout << pC2->Get<int>() << std::endl;
std::cout << pC2->Get<bool>() << std::endl;
delete pC2;
}
Off Topic Unrequested Suggestion: you're using C++11 so... try to avoid the direct use of pointer and try to use smart pointers (std::unique_ptr, std::shared_ptr, etc.) instead.
First of all I think you shouldn't write your own variadic class as we already have std::tuplein place.
I wonder that you sit on c++11because it is quite old. Even c++14is outdated but if you can switch, the solution is very simple:
template < typename DATA, typename FILTER, std::size_t... Is>
auto Subset_Impl( const DATA& data, FILTER& filter, std::index_sequence<Is...> )
{
filter = { std::get< typename std::remove_reference<decltype( std::get< Is >( filter ))>::type>( data )... };
}
template < typename DATA, typename FILTER, typename IDC = std::make_index_sequence<std::tuple_size<FILTER>::value >>
auto Subset( const DATA& data, FILTER& filter )
{
return Subset_Impl( data, filter, IDC{} );
}
int main()
{
std::tuple< int, float, std::string, char > data { 1, 2.2, "Hallo", 'c' };
std::tuple< float, char > filter;
Subset( data, filter );
std::cout << std::get<0>( filter ) << " " << std::get<1>( filter ) << std::endl;
}
If you really want sit on outdated standards, you can easily implement the missing parts from the standard library your self. One related question is answered here: get part of std::tuple
How the helper templates are defined can also be seen on: https://en.cppreference.com/w/cpp/utility/integer_sequence
I'm trying to pack my object to 64 bytes (homegrown properties), and I need to save getter and setter member functions.
I really like std::function but is way big:
sizeof(std::function<int(void)>) gives 40 bytes (VS2017, x64).
I'm trying to figure out is there any thin version of std::function 16 bytes large and without extra allocations inside?
Update: Solution looks like this, it takes 16 bytes (x64) for two member functions.
Member function pointers became template argument so they take nothing, stored just object pointer and vptr.
Thanks to #Yakk.
class Property
{
public:
virtual ~Property() {}
virtual QVariant value() const = 0;
virtual void setValue(const QVariant& value) = 0;
};
template<typename TYPE,
typename CLASS,
TYPE(CLASS::*get)() const,
void(CLASS::*set)(const TYPE &)>
class PropertyValue : public Property
{
public:
PropertyValueGet() = delete;
PropertyValueGet(PropertyValueGet const& ) = delete;
PropertyValueGet& operator=(PropertyValueGet const& ) = delete;
PropertyValueGet(CLASS* object) : m_object(object) {}
TYPE getValue() const {
return (m_object->*get)();
}
void setValue(const TYPE& value) {
(m_object->*set)(value);
}
// Property implementation
//
virtual QVariant value() const final {
QVariant v = QVariant::fromValue<TYPE>(getValue());
return v;
}
virtual void setValue(const QVariant& value) final {
setValue(value.value<TYPE>());
}
private:
CLASS* m_object = nullptr;
};
The type of m_getter is decltype(m_getter).
Using std::mem_fn in Modern C++ is a bad idea - lambda expressions are a cleaner and more transparent (both to the developer and the compiler) way of binding arguments.
Stephan T. Lavavej, in the talk “functional: What's New, And Proper Usage", mentions some drawbacks of std::bind and std::mem_fn compared to lambdas:
You should use a lambda expression instead. E.g.:
auto my_getter = [](Foo& foo){ return foo.getter(); };
Foo some_foo;
my_getter(some_foo);
or
Foo some_foo;
auto my_getter = [&some_foo](){ return some_foo.getter(); };
my_getter();
&Foo::getter has a type, it is TYPE(Foo::*)(void), which is most likely a smaller type than std::function<TYPE(void)>. Similarly &Foo::setter is a void(Foo::*)(TYPE).
But you can get even smaller, by discarding the errant notion that getters and setters are encapsulation, with &Foo::field, which is a TYPE Foo::*.
template<typename T, typename C>
struct Property
{
Property(T C::*member) : member(member) {}
T & get(C & c) { return std::invoke(member, c); }
void set(C & c, T & t) { std::invoke(member, c) = t; }
private:
T C::* member;
}
Alternately accompanying an instance
template<typename T, typename C>
struct Property
{
Property(T C::*member, C & instance) : member(member), instance(instance) {}
T & get() { return std::invoke(member, instance); }
void set(T & value) { std::invoke(member, instance) = value; }
private:
T C::* member;
C & instance;
}
The OP has clarified that the members used are fixed:
template<class T>
struct generic_property {
virtual T getValue() const = 0;
virtual void setValue(T const&) = 0;
protected:
virtual ~generic_property() {}
};
template<class D, class T, void(D::*set)(T const&), T(D::*get)() const>
struct property:generic_property<T> {
T getValue() const final {
return (self->*get)();
}
void setValue(T const& t) final {
(self->*set)(t);
}
property( D* s ):self(s) {}
// cannot usually safely copy/move/trivial:
property() = delete;
property( property const& ) = delete;
property& operator=( property const& ) = delete;
private:
D* self = 0;
};
struct Bob {
void setFoo( int const& i ) { std::cout << i << " set\n"; }
int getFoo() const { std::cout << 42 << " get\n"; return 42; }
property<Bob, int, &Bob::setFoo, &Bob::getFoo> foo;
Bob():foo(this) {}
};
each property takes up 1 pointers worth of space (so 32 to 64 bits, or 4-8 bytes, depending on the bit-width of the OS).
Adding virtual and generic_property<T> makes it take up another pointer's worth of space.
live example.
We could type erase manually in generic_property instead of by virtual inheritance.
This is a c++17 answer, because doing this in c++11 is really annoying.
Here is a "simple" stateless view-only std::function.
// utility tag type for dispatching
template<class Tag>
struct tag_t {};
// helper type to find the "caller" function pointer used to erase invoke:
template<class Sig>
struct caller_type;
template<class R, class...Args>
struct caller_type<R(Args...)> {
using type = R(*)(void*, Args&&...);
};
template<class Sig>
using caller = typename caller_type<Sig>::type;
// make a caller<Sig> that type erases calling T with Sig:
template<class T, class Sig>
struct make_caller;
template<class T, class R, class...Args>
struct make_caller<T, R(Args...)> {
caller<R(Args...)> operator()() const {
return [](void* ptr, Args&&...args)->R {
return (*static_cast<T*>(ptr))( std::forward<Args>(args)... );
};
}
};
template<class T, class...Args>
struct make_caller<T, void(Args...)> {
caller<void(Args...)> operator()() const {
return [](void* ptr, Args&&...args)->void {
(*static_cast<T*>(ptr))( std::forward<Args>(args)... );
};
}
};
// provides operator() overload compatible with Sig,
// then dispatches the call down through a derived type D:
template<class D, class Sig>
struct call_dispatch;
template<class D, class R, class...Args>
struct call_dispatch<D, R(Args...)> {
R operator()(Args...args)const {\
auto* caller = self()->get_caller(tag_t<R(Args...)>{});
return (*caller)( self()->pvoid(), std::forward<Args>(args)... );
}
auto self() { return static_cast<D*>(this); }
auto self() const { return static_cast<D const*>(this); }
};
// stores a function pointer to invoke Sig
template<class Sig>
struct call_storage {
caller<Sig> f = nullptr;
template<class T>
static call_storage make() {
return {make_caller<T, Sig>{}()};
}
caller<Sig> get_caller( tag_t<Sig> ) const { return f; }
};
// a table of such function pointers
template<class...Sig>
struct call_vtable:call_storage<Sig>... {
template<class T>
static call_vtable make() {
return {call_storage<Sig>::template make<T>()...};
}
using call_storage<Sig>::get_caller...;
};
// overload helper to dispatch to correct Sig:
template<class D, class...Sig>
struct call_dispatcher:
call_dispatch<D, Sig>...
{
using call_dispatch< D, Sig >::operator()...;
};
// Erases invoking but not storing an arbitrary type T
// with all of ...Sig. Stores the invokers inside itself,
// not in an external vtable, to increase locality at the cost
// of per-instance size:
template<class... Sig>
struct call_view_t:
private call_vtable<Sig...>,
call_dispatcher< call_view_t<Sig...>, Sig... >
{
template<class F,
std::enable_if_t<!std::is_same<std::decay_t<F>, call_view_t>{}, bool> =true
>
call_view_t( F&& f ):
call_vtable<Sig...>( call_vtable<Sig...>::template make<std::decay_t<F>>() ),
ptr( std::addressof(f) )
{}
call_view_t()=default;
call_view_t(call_view_t const&)=default;
call_view_t& operator=(call_view_t const&)=default;
explicit operator bool() const { return ptr != nullptr; }
void* pvoid() const { return ptr; }
using call_vtable<Sig...>::get_caller;
private:
void* ptr = 0;
};
it requires 2 pointers, one to store non-owning state and one to store an invoker (it also supports any number of signatures on the thing to invoke).
We can create a new call_view type that instead of storing a ptr*, stores a block of memory; in that block, it placement new's the state of the F passed in and pvoid() returns a pointer to it.
Unless you restrict yourself to trivial destruction and copy/move, you'll also have to store pointers to functions on how to do that.
As call_impl only varies based on the type of thing stored and not its value, we can store the f's in a vtable and only inherit from call_dispatch. Inside that vtable we can store copy/move/destroy of our copy of F.
This permits us to have a trim std::function with state that only requires 1 pointer overhead over the storage of whatever state you want to put in the std::function.
Note that the above code probably has typos, and doesn't solve your problem. It has 9/10 of the pieces to solve your problem.
// a vtable that represents "I can be copied or moved and destroyed":
struct copyable_vtable {
void(*dtor)(void*)=0;
void(*copy)(void* dest, void const* src)=0;
void(*move)(void* dest, void* src)=0;
template<class T>
static copyable_vtable make() {
return {
[](void* ptr){ static_cast<T*>(ptr)->~T(); },
[](void* dest, void const* src){
::new( dest ) T(*static_cast<T const*>(src));
},
[](void* dest, void * src){
::new( dest ) T(std::move(*static_cast<T const*>(src)));
}
};
}
};
// the vtable that our "small function" needs:
template<class...Sig>
struct small_func_vtable:
copyable_vtable,
call_vtable<Sig...>
{
template<class T>
static small_func_vtable make() {
return {
copyable_vtable::template make<T>(),
call_vtable<Sig...>::template make<T>()
};
}
template<class T>
static small_func_vtable const* get() {
static const auto vtable = make<T>();
return &vtable;
}
};
// bundles up the size and alignment requirements:
template<std::size_t S=sizeof(void*)*3, std::size_t A=alignof(void*)>
struct size_params {
enum { size = S, align = A };
};
// A small stack allocated std::function that refuses to get bigger
// If you try to construct it with something larger, you get
// a static assert failure. Also supports arbitrary number of
// overloads of ():
template<class Size, class...Sig>
struct small_function:
call_dispatcher< small_function<Size, Sig...>, Sig... >
{
private:
small_func_vtable<Sig...> const* vtable = 0;
mutable std::aligned_storage_t< Size::size, Size::align > data;
public:
template<class F,
std::enable_if_t<!std::is_same<std::decay_t<F>, small_function>{}, bool> =true
>
small_function( F&& f )
{
static_assert( sizeof(std::decay_t<F>)<=Size::size );
static_assert( alignof(std::decay_t<F>)<=Size::align );
::new( (void*)&data ) std::decay_t<F>( std::forward<F>(f) );
vtable = small_func_vtable<Sig...>::template get<std::decay_t<F>>();
}
small_function()=default;
// we could refactor this into base class:
small_function(small_function const& o) {
if (!o.vtable) return;
o.vtable->copy( pvoid(), o.pvoid() );
vtable = o.vtable;
}
small_function(small_function&& o) {
if (!o.vtable) return;
o.vtable->move( pvoid(), o.pvoid() );
vtable = o.vtable;
}
small_function& operator=(small_function const& o) {
if (this == &o) return *this;
if (vtable) {
vtable->dtor(pvoid());
vtable = nullptr;
}
if (o.vtable) {
o.vtable->copy( pvoid(), o.pvoid() );
vtable = o.vtable;
}
return *this;
}
small_function& operator=(small_function&& o) {
if (this == &o) return *this;
if (vtable) {
vtable->dtor(pvoid());
vtable = nullptr;
}
if (o.vtable) {
o.vtable->move( pvoid(), o.pvoid() );
vtable = o.vtable;
}
return *this;
}
// use null vtable to determine if we are empty:
explicit operator bool() const { return vtable != nullptr; }
// these must be visible to dispatch system. I think
// they are harmless to expose to end users, so I don't bother
// with making them private and friending dispatch system:
void* pvoid() const { return &data; }
template<class S>
caller<S> get_caller(tag_t<S> t) const {
if (!vtable) return nullptr;
return vtable->get_caller(t);
}
};
template<class...Sig>
using simple_small_function = small_function< size_params<>, Sig... >;
and try simple_small_function.
Live example.
Let's look at what we need for std::function:
A pointer for the list of how to copy, destroy, and invoke the payload. Knowledge of the targets type and how to retrieve it is a bonus, and extra cost per type is marginal (none per instance).
The target. To avoid rampant allocating, there should be space for at least a member-function-pointer. Unfortunately, the conforming format MSVC uses is a whomping 4 pointers big (they use different smaller non-conforming ones in different situations). Other ABIs use smaller ones for full effect.
So, that's 5 pointers worth => 5*8 = 40 Bytes on 64 bit Windows as a minimum to accomodate member-function-pointers.
How to handle an api which returns different data types for the same input data types?
Looking at the below example, apicall should return a date or a string depending on the input attribute:
#include <iostream>
#include <string>
using namespace std;
???? apicall(string datatype, string attribute)
{
// code
}
int main(int argc, char** argv)
{
string datatype = "Thomas"
string attribute = "bithday"
cout << apicall(datatype, attribute) << endl;
string datatype = "Thomas"
string attribute = "address"
cout << apicall(datatype, attribute) << endl;
}
What could be in place of ???? (apicall return datatype) and how to handle these cases?
I am trying to understand these concepts as my experience to date has been with duck typed scripting languages.
The ideal solution is to use a std::variant, which is a safe union type like.
This allows you to write the following:
using DateOrString = std::variant<DateType, std::string>;
DateOrString api_call(std::string, std::string) {
// you can return both DateType and std::string
}
// ...
auto result = api_call("", "");
auto& str = std::get<std::string>(result);
Unfortunately std::variant is a C++17 feature. However different compilers already support it.
As already has been suggested, boost has a variant class and you can use it with any C++ standard.
As last option, you may implement a "variant-like" class which handles both a date and a string. Your function should return it.
Here a demo how to quickly implement that kind of class.
Note that that class is safe because the type is checked at runtime.
As a variant object, your callee function should branch on the type, something like:
auto result = api_call(/*...*/);
if (result.is_string()) {
// result is a string
const auto& str = result.get_string();
} else {
// result is a date
const auto& date = result.get_date();
}
... returns different data types for the same input data types?
This is literally impossible. A function is defined with one (or zero) return types, and zero or more input parameter types.
The workarounds are:
Write a single function returning a variant type, such as std::variant in C++17, or Boost.Variant if that's not available.
Write multiple functions with different return types (the caller just has to choose the right one)
Invert control, so that instead of returning a value, you pass an object capable of processing all the required types:
struct APIHandler {
virtual ~APIHandler() {}
virtual void operator()(int) {}
virtual void operator()(string) {}
};
void apicall(string name, string attr, APIHandler &h) {
// dummy implementation
if (attr == "address") {
h("123 Woodford Road");
} else if (attr == "birthday") {
h(19830214);
}
}
// implement your type-specific logic here
struct MyHandler: APIHandler {
void operator()(int i) override {
cout << "got an int:" << i << '\n';
}
void operator()(string s) override {
cout << "got a string:" << s << '\n';
}
};
// and use it like:
MyHandler mh;
apicall("Thomas", "birthday", mh);
apicall("Thomas", "address", mh);
You want a std::variant in C++17 or a boost::variant or roll your own crude variant something like this:
constexpr std::size_t max() { return 0; }
template<class...Ts>
constexpr std::size_t max( std::size_t t0, Ts...ts ) {
return (t0<max(ts...))?max(ts...):t0;
}
template<class T0, class...Ts>
struct index_of_in;
template<class T0, class...Ts>
struct index_of_in<T0, T0, Ts...>:std::integral_constant<std::size_t, 0> {};
template<class T0, class T1, class...Ts>
struct index_of_in<T0, T1, Ts...>:
std::integral_constant<std::size_t,
index_of_in<T0, Ts...>::value+1
>
{};
struct variant_vtable {
void(*dtor)(void*) = 0;
void(*copy)(void*, void const*) = 0;
void(*move)(void*, void*) = 0;
};
template<class T>
void populate_vtable( variant_vtable* vtable ) {
vtable->dtor = [](void* ptr){ static_cast<T*>(ptr)->~T(); };
vtable->copy = [](void* dest, void const* src){
::new(dest) T(*static_cast<T const*>(src));
};
vtable->move = [](void* dest, void* src){
::new(dest) T(std::move(*static_cast<T*>(src)));
};
}
template<class T>
variant_vtable make_vtable() {
variant_vtable r;
populate_vtable<T>(&r);
return r;
}
template<class T>
variant_vtable const* get_vtable() {
static const variant_vtable table = make_vtable<T>();
return &table;
}
template<class T0, class...Ts>
struct my_variant {
std::size_t index = -1;
variant_vtable const* vtable = 0;
static constexpr auto data_size = max(sizeof(T0),sizeof(Ts)...);
static constexpr auto data_align = max(alignof(T0),alignof(Ts)...);
template<class T>
static constexpr std::size_t index_of() {
return index_of_in<T, T0, Ts...>::value;
}
typename std::aligned_storage< data_size, data_align >::type data;
template<class T>
T* get() {
if (index_of<T>() == index)
return static_cast<T*>((void*)&data);
else
return nullptr;
}
template<class T>
T const* get() const {
return const_cast<my_variant*>(this)->get<T>();
}
template<class F, class R>
using applicator = R(*)(F&&, my_variant*);
template<class T, class F, class R>
static applicator<F, R> get_applicator() {
return [](F&& f, my_variant* ptr)->R {
return std::forward<F>(f)( *ptr->get<T>() );
};
}
template<class F, class R=typename std::result_of<F(T0&)>::type>
R visit( F&& f ) & {
if (index == (std::size_t)-1) throw std::invalid_argument("variant");
static const applicator<F, R> table[] = {
get_applicator<T0, F, R>(),
get_applicator<Ts, F, R>()...
};
return table[index]( std::forward<F>(f), this );
}
template<class F,
class R=typename std::result_of<F(T0 const&)>::type
>
R visit( F&& f ) const& {
return const_cast<my_variant*>(this)->visit(
[&f](auto const& v)->R
{
return std::forward<F>(f)(v);
}
);
}
template<class F,
class R=typename std::result_of<F(T0&&)>::type
>
R visit( F&& f ) && {
return visit( [&f](auto& v)->R {
return std::forward<F>(f)(std::move(v));
} );
}
explicit operator bool() const { return vtable; }
template<class T, class...Args>
void emplace( Args&&...args ) {
clear();
::new( (void*)&data ) T(std::forward<Args>(args)...);
index = index_of<T>();
vtable = get_vtable<T>();
}
void clear() {
if (!vtable) return;
vtable->dtor( &data );
index = -1;
vtable = nullptr;
}
~my_variant() { clear(); }
my_variant() {}
void copy_from( my_variant const& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->copy( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
void move_from( my_variant&& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->move( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
my_variant( my_variant const& o ) {
copy_from(o);
}
my_variant( my_variant && o ) {
move_from(std::move(o));
}
my_variant& operator=(my_variant const& o) {
copy_from(o);
return *this;
}
my_variant& operator=(my_variant&& o) {
move_from(std::move(o));
return *this;
}
template<class T,
typename std::enable_if<!std::is_same<typename std::decay<T>::type, my_variant>{}, int>::type =0
>
my_variant( T&& t ) {
emplace<typename std::decay<T>::type>(std::forward<T>(t));
}
};
then your code looks like:
variant<string, int> apicall(string datatype, string attribute)
{
if (datatype > attribute) return string("hello world");
return 7;
}
int main()
{
string datatype = "Thomas"
string attribute = "bithday"
apicall(datatype, attribute).visit([](auto&&r){
cout << r << endl;
});
string datatype = "Thomas"
string attribute = "address"
apicall(datatype, attribute).visit([](auto&& r){
cout << r << endl;
});
}
with whatever visit or apply_visitor free function or method your particular variant supports.
This gets much more annoying in C++11 as we don't have generic lambdas.
You could use a variant, but it's up to the caller site to check the results. Boost and std defines two variant types, i.e. std::variant and std::any.
I'm trying to write a class Invocation which has a templated constructor:
template<typename F>
class Invocation {
public:
template<typename... Args>
Invocation(F&& f, Args&&... args)
{ /* store f and args somewhere for later use */ }
...
};
Normally I would parameterize the Invocation class itself with both F and Args..., but in this case I need a uniform type for a given F, so I'm trying to find a way to store args... of any types inside a Invocation<F>, and to incur as little performance hit as possible. (This might not be the best design, but it can be an interesting exercise.)
One thought is to use virtual functions:
template<typename F>
class ArgsBase {
public:
// discard return value
virtual void invoke(F&& f) = 0;
};
template<typename F, typename... Ts>
class Args : public ArgsBase<F> {
public:
Args(Ts&&... args) : args_(std::forward<Ts>(args)...) {}
void invoke(F&& f) override
{
/* somehow call f with args_ (something like std::apply) */
...
}
private:
std::tuple<Ts&&...> args_;
};
And then in the Invocation<F> class, we can for example have an std::unique_ptr<ArgsBase<F>> member, which points to an Args<F, Ts...> object created in the Invocation<F> ctor. And we can call its invoke virtual method when needed.
This is just one random idea I came up with. Is there any other way to achieve this? Ideally without the overhead of virtual functions or anything like that?
UPDATE: Thanks to the comments/answers that suggest using std::function or lambdas. I should've made it clear that I'm actually interested in a more general case, i.e., the variadic stuff might not be arguments to a callable. It can be just anything that I want to store in a class whose type is not parameterized by the types of these stuff.
As mentioned in comment, I wouldn't worry about storing arguments by value. The compiler's copy-elision can be generous.
Particularly if you offer the class an r-value invoke:
#include <tuple>
template<typename F>
class ArgsBase {
public:
// discard return value
virtual void invoke(F&& f) const & = 0;
virtual void invoke(F&& f) && = 0;
};
template<typename F, class... FunctionArgs>
class Args : public ArgsBase<F> {
public:
template<class...Ts>
Args(Ts&&... args) : args_(std::forward<Ts>(args)...) {}
template<std::size_t...Is, class Tuple>
static void invoke_impl(F& f, std::index_sequence<Is...>, Tuple&& t)
{
f(std::get<Is>(std::forward<Tuple>(t))...);
}
void invoke(F&& f) const & override
{
invoke_impl(f,
std::make_index_sequence<std::tuple_size<tuple_type>::value>(),
args_);
/* somehow call f with args_ (something like std::apply) */
}
void invoke(F&& f) && override
{
invoke_impl(f,
std::make_index_sequence<std::tuple_size<tuple_type>::value>(),
std::move(args_));
/* somehow call f with args_ (something like std::apply) */
}
private:
using tuple_type = std::tuple<FunctionArgs...>;
tuple_type args_;
};
template<class Callable, class...MyArgs>
auto later(MyArgs&&...args) {
return Args<Callable, std::decay_t<MyArgs>...>(std::forward<MyArgs>(args)...);
}
void foo(const std::string&, std::string)
{
}
int main()
{
auto l = later<decltype(&foo)>(std::string("hello"), std::string("world"));
l.invoke(foo);
std::move(l).invoke(foo);
}
If you're trying to save a function call with its parameters for later invocation, you could use lambdas packaged in std::function objects:
template<typename F, typename ... Args>
std::function<void()> createInvocation(F f, const Args& ... args)
{
return [f,args...]() { f(args...); };
}
Then you could use it like this:
void myFunc(int a, int b)
{
std::cout << "Invoked: " << a + b << std::endl;
}
int main() {
auto invocation = createInvocation(myFunc, 1, 2);
invocation();
return 0;
}
UPDATE: If you wanted to create a generic non-templated container type, you can wrap a tuple into a type that itself derives from a non-templated type. The main problem then is accessing the underlying data. This can be solved by creating a static function dispatch table that for a given tuple type, redirects queries so that std::get, which requires a compile-time constant index template parameter, can instead be invoked with a dynamically provided function parameter. Here is an implementation that achieves this:
class GenericTupleContainer
{
public:
virtual const void* getItemAtIndex(size_t index) = 0;
};
template<typename ... T>
class TupleContainer : public GenericTupleContainer
{
public:
TupleContainer(T&& ... args)
: data(std::forward<T>(args)...)
{}
const void* getItemAtIndex(size_t index) override
{
if(index >= sizeof...(T))
throw std::runtime_error("Invalid index");
return dispatchTable[index](data);
}
private:
template<size_t index>
static const void* getItemAtIdx(const std::tuple<T...>& data)
{
return &std::get<index>(data);
}
using GetterFn = const void*(*)(const std::tuple<T...>&);
static GetterFn* initDispatchTable()
{
static GetterFn dispatchTable[sizeof...(T)];
populateDispatchTable<sizeof...(T)>(dispatchTable, std::integral_constant<bool, sizeof...(T) == 0>());
return dispatchTable;
}
static GetterFn* dispatchTable;
template<size_t idx>
static void populateDispatchTable(GetterFn* table, std::false_type);
template<size_t idx>
static void populateDispatchTable(GetterFn* table, std::true_type)
{
//terminating call - do nothing
}
std::tuple<T...> data;
};
template<typename ... T>
typename TupleContainer<T...>::GetterFn* TupleContainer<T...>::dispatchTable = TupleContainer<T...>::initDispatchTable();
template<typename ... T>
template<size_t idx>
void TupleContainer<T...>::populateDispatchTable(GetterFn* table, std::false_type)
{
table[idx-1] = &TupleContainer<T...>::template getItemAtIdx<idx-1>;
populateDispatchTable<idx-1>(table, std::integral_constant<bool, idx-1 == 0>() );
}
template<typename ... T>
auto createTupleContainer(T&& ... args)
{
return new TupleContainer<T...>(std::forward<T>(args)...);
}
Then you can use the above as follows:
int main() {
GenericTupleContainer* data = createTupleContainer(1, 2.0, "Hello");
std::cout << *(static_cast<const int*>(data->getItemAtIndex(0))) << std::endl;
std::cout << *(static_cast<const double*>(data->getItemAtIndex(1))) << std::endl;
std::cout << (static_cast<const char*>(data->getItemAtIndex(2))) << std::endl;
return 0;
}
As you can see from the above usage, you've achieved the aim of wrapping an arbitrary templated tuple into a non-templated type, in such a way that you can access the component members with a normal (function) index parameter instead of a template one. Now the return type of such a getter has to be universal, so I've chosen to use void* here, which is not ideal. But you can develop this idea to make this container give more useful information about the types of its data tuple members. Also, note that this does use a virtual function. With some further work you can get rid of this as well, although you won't be able to get rid of at least one function pointer lookup (i.e. the lookup in the dispatch table) - this is the price paid for gaining the flexibility of being able to use a runtime value to index into the tuple.