Trying to avoid code duplication for some specific C++ code - c++

I have some C++ code which consists of repeats of the following pattern:
int Func(Type1 arg1, Type2 arg2)
{
RAIILock lock(Singleton::Mutex());
Instance* ptr = GetClassInstance();
if (ptr) {
return ptr->Func(arg1, arg2);
} else {
return -1;
}
}
Basically, it's trying to get a valid class instance pointer under the lock, and essentially forwarding the call from this normal function to an instance method with the same signature. The "Func" name as well as amount and type of arguments vary, but the rest of the calls are identical.
It feels like there should be some way to achieve this using templates without getting into too much template magic, but I've been unable to come up with anything.

Something like that?
template <class MEM_FUN, class... ARGS>
auto call_func(MEM_FUN&& f, ARGS&&... args)
{
RAIILock lock(Singleton::Mutex());
Instance* ptr = GetClassInstance();
if (ptr) {
return (ptr->*f)(std::forward<ARGS>(args)...);
} else {
return -1;
}
}
Calling like this:
call_func(&Instance::Func, arg1, arg2, arg3);

I would start with this primitive:
template<class F>
std::result_of_t<F(Instance*)> while_locked( F&& f ) {
RAIILock lock(Singleton::Mutex());
Instance* ptr = GetClassInstance();
if (ptr)
return std::forward<F>(f)(ptr):
else
return -1;
}
use:
int x = while_locked( [&](auto* ptr) {
ptr->foo( a, b );
} );
basically, you get the ability to do whatever you want while locked, and have access to a ptr while doing it. This lets you merge multiple method calls into one atomic operation.
This can be extended to a multi-ary while-locked, that does an ordering of mutexes on a set of ptr-sources, locks them appropriately, gets the pointers from each, then invokes your function.
It also becomes easy to write your "invoke a member function" version, but restricting your atomic operations to "only call some specific member function" seems questionable.
I will admit the syntax is nicer in C++14 than in C++11 with auto-lambda. But most major compilers have implemented auto-lambda by this point.
There is a more general pattern that looks like this:
template<class T>
struct lockable {
template<class F>
std::result_of_t<F(T const&)> read( F&& f ) const {
auto l = lock();
return std::forward<F>(f)(t);
}
template<class F>
std::result_of_t<F(T&)> write( F&& f ) {
auto l = lock();
return std::forward<F>(f)(t);
}
private:
using read_lock_t = std::shared_lock<std::shared_mutex>;
using write_lock_t = std::unique_lock<std::shared_mutex>;
read_lock_t lock() const { return read_lock_t(m); }
write_lock_t lock() { return write_lock_t(m); }
mutable std::shared_mutex m;
T t;
};
which can be augmented with operator=, copy-ctor, move-ctors, default-ctors, and multi-locking capabilities. Multi-locking comes from std::lock and creation of unlocked lockables.
read_lock_t unlocked() const { return {m, std::defer_lock}; }
write_lock_t unlocked() { return {m, std::defer_lock}; }
template<size_t...Is, class...Selfs>
friend auto lock_all( std::index_sequence<Is...>, Selfs&... selfs ) {
auto r = std::make_tuple( selfs.unlocked() );
std::lock( std::get<Is>(r)... );
return r;
}
template<class...Selfs>
friend auto lock_all( Selfs&... selfs ) {
return lock_all( std::index_sequence_for<Selfs...>{}, selfs... );
}
public:
template<class F, class...Selfs>
friend auto invoke( F&& f, Selfs&...selfs )
-> std::result_of_t< F( decltype(selfs.t)... ) >
{
auto l = lock_all(selfs...);
return std::forward<F>(f)(selfs.t...);
}
which lets you do invoke( lambda, a, b, c ) which will lock a b and c using the appropriate lock for their const-ness, and then invoke the lambda.
This allows easy writing of operator= for example:
lockable& operator=( lockable&& o ) {
if (this = std::addressof(o)) return *this;
return invoke( [](T& target, T& src){
return target = std::move(src);
}, *this, o );
}
lockable& operator=( lockable const& o ) {
if (this = std::addressof(o)) return *this;
return invoke( [](T& target, T const& src){
return target = src;
}, *this, o );
}

You might not apply too much convenience and have a guarded singleton allowing multiple member function calls:
#include <mutex>
template <typename T>
class Lockable
{
template <typename> friend class Lock;
public:
typedef std::mutex mutex_type;
typedef std::lock_guard<std::mutex> lock_guard;
public:
Lockable()
{}
template <typename A>
Lockable(A&& a)
: _value(std::forward<A>(a))
{}
template <typename A, typename ... Args>
Lockable(A&& a, Args&& ... args)
: _value(std::forward<A>(a), std::forward<Args>(args)...)
{}
Lockable(const Lockable&) = delete;
Lockable& operator = (const Lockable&) = delete;
explicit operator T () const {
lock_guard lock(_mutex);
T result = _value;
return result;
}
Lockable& operator = (const T& value) {
lock_guard lock(_mutex);
_value = value;
return *this;
}
private:
mutable mutex_type _mutex;
T _value;
};
template <typename T>
class Lock
{
public:
typedef Lockable<T> lockable_type;
typedef typename lockable_type::mutex_type mutex_type;
typedef typename lockable_type::lock_guard lock_guard;
public:
Lock(lockable_type& lockable)
: _lock(lockable._mutex), _ptr(&(lockable._value))
{}
Lock(const Lock&) = delete;
Lock& operator = (const Lock&) = delete;
operator T& () const { return *_ptr; }
T& operator * () const { return *_ptr; }
T* operator -> () const { return _ptr; }
private:
lock_guard _lock;
T* _ptr;
};
class Singleton
{
private:
friend class Lockable<Singleton>;
Singleton() {};
public:
Singleton(const Singleton&) = delete;
Singleton& operator = (const Singleton&) = delete;
static Lockable<Singleton>& instance();
int Func0(int arg) const { return 0; }
int Func1(int arg) const { return 1; }
int Func2(int arg) const { return 2; }
};
Lockable<Singleton>& Singleton::instance() {
static Lockable<Singleton> result;
return result;
}
#include <iostream>
int main() {
Lock<Singleton> singleton(Singleton::instance());
singleton->Func0(0);
singleton->Func1(1);
singleton->Func2(2);
std::cout << "Reached\n";
// Uncomment to get a deadlock
// Lock<Singleton> deadlock_singleton(Singleton::instance());
// std::cout << "Not reached\n";
return 0;
}
Note: The Lock<Singleton> singleton(Singleton::instance()); is clumsy, due to the non moveable std::lock_guard.

Related

Thin replacement for fat std::function

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?

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.

C++: how can I overload a function so that it can take any functor, including pointer to member functions?

In order to broaden my understanding of C++11, I'm experimenting with writing functional helpers and seeing if I can make calling them less verbose. Right now I'm trying to write a some function that returns true if any item in a collection passes a test. I want it to work with any collection type, be able to take any callable, and not require template arguments.
Essentially, I want it to work such that the following code will compile:
// insert declaration of some here
#include <list>
#include <functional>
class Foo {
public:
bool check() const { return true; };
};
class DerivedFooList : public std::list<Foo> {
public:
DerivedFooList(std::initializer_list<Foo> args) : std::list<Foo>(args) {};
};
class DerivedFooPtrList : public std::list<Foo *> {
public:
DerivedFooPtrList(std::initializer_list<Foo *> args) : std::list<Foo *>(args) {};
};
bool intCheck(int a) { return a == 1; }
bool fooCheck(const Foo &a) { return a.check(); }
bool fooPtrCheck(const Foo *a) { return a->check(); }
int main()
{
Foo a, b, c;
std::list<int> intList = {1, 2, 3};
std::list<Foo> fooList = {a, b, c};
std::list<Foo *> fooPtrList = {&a, &b, &c};
DerivedFooList derivedFooList = {a, b, c};
DerivedFooPtrList derivedFooPtrList = {&a, &b, &c};
auto localIntCheck = [] (int a) { return a == 1; };
auto localFooCheck = [] (const Foo &a) { return a.check(); };
auto localFooPtrCheck = [] (const Foo *a) { return a->check(); };
some(intList, [] (int a) { return a == 1; });
some(intList, &intCheck);
some(intList, localIntCheck);
some(fooList, [] (const Foo &a) { return a.check(); });
some(fooList, &fooCheck);
some(fooList, localFooCheck);
some(fooList, &Foo::check);
some(fooPtrList, [] (const Foo *a) { return a->check(); });
some(fooPtrList, &fooPtrCheck);
some(fooPtrList, localFooPtrCheck);
some(fooPtrList, &Foo::check);
some(derivedFooList, [] (const Foo &a) { return a.check(); });
some(derivedFooList, &fooCheck);
some(derivedFooList, localFooCheck);
some(derivedFooList, &Foo::check);
some(derivedFooPtrList, [] (const Foo *a) { return a->check(); });
some(derivedFooPtrList, &fooPtrCheck);
some(derivedFooPtrList, localFooPtrCheck);
some(derivedFooPtrList, &Foo::check);
return 0;
}
Note that if the value type of the collection is an object or object pointer, I want to be able to pass a pointer to a member function as the second argument to some. And that's where things get hairy.
My first attempt was to implement it like this:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <template<class, class> class T, class U, class V, class W>
bool some(const T<U, V> &list, bool (W::*func)() const)
{
return some(list, [=](U const &t){ return (t.*func)(); });
}
template <template<class, class> class T, class U, class V, class W>
bool some(const T<U *, V> &list, bool (W::*func)() const)
{
return some(list, [=](U const *t){ return (t->*func)(); });
}
...but it doesn't work if the collection is not an STL collection, or at least one that takes two template arguments. In my example, using DerivedFooList or DerivedFooPtrList won't work.
My second attempt looked like this:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <class T, class U>
bool some(const T &list, bool (U::*func)() const)
{
return some(list, [=](U const &t) { return (t.*func)(); });
}
That works with DerivedFooList now, but doesn't work with std::list<Foo *> or DerivedFooPtrList.
My third attempt was this:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <class T, class U>
bool some(typename std::enable_if<std::is_class<typename T::value_type>::value, T>::type const &list, bool (U::*func)() const)
{
return some(list, [=](U const &t) { return (t.*func)(); });
}
template <class T, class U>
bool some(typename std::enable_if<std::is_pointer<typename T::value_type>::value, T>::type const &list, bool (U::*func)() const)
{
return some(list, [=](U const *t) { return (t->*func)(); });
}
Ignoring for the time being that this would only work with collections that have a member named value_type, it still doesn't allow my above example to compile. I think (but am not 100% sure) the reason is that it can't deduce T for the second two versions of some for the cases where I want it to be used.
I've tried very hard to see if there's a way to get what I want out of C++11, and I suspect that there is, but I can't figure it out. Is what I want possible, and if so, how do I do it?
template<class R, class F>
bool some( R const& r, F&& f ) {
for(auto&& x:r)
if (std::ref(f)(decltype(x)(x)))
return true;
return false;
}
std::ref overloads () to do the INVOKE concept, which in C++17 can be accessed directly via std::invoke. Your requirements seem to line up with the INVOKE concept.
decltype(x)(x) is equivalent to a std::forward expression if x is a deduced auto&& variable. Read it as "treat x as if it was the type it was declared as". Note that if x is an auto value, it copies, unlike forward.
INVOKE( pmf, ptr ) and INVOKE( pmf, ref ) both work. So no need to do fancy stuff in the overload.

Using std::variant with recursion, without using boost::recursive_wrapper

I'd like to replace boost::variants with C++17 std::variant and get rid of boost::recursive_wrapper, to remove dependency on boost completely in following code. How may I do that?
#include <boost/variant.hpp>
#include <type_traits>
using v = boost::variant<int, boost::recursive_wrapper<struct s> >;
struct s
{
v val;
};
template<template <typename...> class R, typename T, typename ... Ts>
auto reduce(T t, Ts ... /*ts*/)
{
return R<T, Ts...>{t};
}
template<typename T, typename F>
T adapt(F f)
{
static_assert(std::is_convertible_v<F, T>, "");
return f;
}
int main()
{
int val1 = 42;
s val2;
auto val3 = adapt<v>(reduce<boost::variant>(val1, val2));
}
There are two generic functions: first function reduce chooses at runtime which argument to return (here it just returns first argument for brevity), second function adapt converts a value of type F to a value of type T.
In this example reduce returns an object of type boost::variant<int, s> which is then converted to an object of type boost::variant<int, boost::recursive_wrapper<s> >.
boost::variant will heap allocate in order to have part of itself be recursively defined as itself. (It will also heap allocate in a number of other situations, uncertain how many)
std::variant will not. std::variant refuses to heap allocate.
There is no way to actually have a structure containing a possible variant of itself without a dynamic allocation, as such a structure can easily be shown to be infinite in size if statically declared. (You can encode the integer N by having N recursions of not-the-same: no fixed size buffer can hold an infinite amount of information.)
As such, the equivalent std::variant stores a smart pointer of some kind placeholder of a recursive instance of itself.
This may work:
struct s;
using v = std::variant< int, std::unique_ptr<s> >;
struct s
{
v val;
~s();
};
inline s::~s() = default;
and failing that, try:
struct destroy_s;
struct s;
using v = std::variant<int, std::unique_ptr<s, destroy_s> >;
struct s
{
v val;
~s();
};
struct destroy_s {
void operator()(s* ptr){ delete ptr; }
};
inline s::~s() = default;
It does mean that client code has to knowingly interact with the unique_ptr<s> and not the struct s directly.
If you want to support copy semantics, you'll have to write a value_ptr that does copies, and give it the equivalent of struct copy_s; to implement that copy.
template<class T>
struct default_copier {
// a copier must handle a null T const* in and return null:
T* operator()(T const* tin)const {
if (!tin) return nullptr;
return new T(*tin);
}
void operator()(void* dest, T const* tin)const {
if (!tin) return;
new(dest) T(*tin);
}
};
template<class T, class Copier=default_copier<T>, class Deleter=std::default_delete<T>,
class Base=std::unique_ptr<T, Deleter>
>
struct value_ptr:Base, private Copier {
using copier_type=Copier;
// also typedefs from unique_ptr
using Base::Base;
value_ptr( T const& t ):
Base( std::make_unique<T>(t) ),
Copier()
{}
value_ptr( T && t ):
Base( std::make_unique<T>(std::move(t)) ),
Copier()
{}
// almost-never-empty:
value_ptr():
Base( std::make_unique<T>() ),
Copier()
{}
value_ptr( Base b, Copier c={} ):
Base(std::move(b)),
Copier(std::move(c))
{}
Copier const& get_copier() const {
return *this;
}
value_ptr clone() const {
return {
Base(
get_copier()(this->get()),
this->get_deleter()
),
get_copier()
};
}
value_ptr(value_ptr&&)=default;
value_ptr& operator=(value_ptr&&)=default;
value_ptr(value_ptr const& o):value_ptr(o.clone()) {}
value_ptr& operator=(value_ptr const&o) {
if (o && *this) {
// if we are both non-null, assign contents:
**this = *o;
} else {
// otherwise, assign a clone (which could itself be null):
*this = o.clone();
}
return *this;
}
value_ptr& operator=( T const& t ) {
if (*this) {
**this = t;
} else {
*this = value_ptr(t);
}
return *this;
}
value_ptr& operator=( T && t ) {
if (*this) {
**this = std::move(t);
} else {
*this = value_ptr(std::move(t));
}
return *this;
}
T& get() { return **this; }
T const& get() const { return **this; }
T* get_pointer() {
if (!*this) return nullptr;
return std::addressof(get());
}
T const* get_pointer() const {
if (!*this) return nullptr;
return std::addressof(get());
}
// operator-> from unique_ptr
};
template<class T, class...Args>
value_ptr<T> make_value_ptr( Args&&... args ) {
return {std::make_unique<T>(std::forward<Args>(args)...)};
}
Live example of value_ptr.

How to convert std::future<T> to std::future<void>?

I have a situation where I have a std::future<some_type> resulting from a call to API A, but need to supply API B with a std::future<void>:
std::future<some_type> api_a();
void api_b(std::future<void>& depend_on_this_event);
In the absence of proposed functionality such as .then() or when_all(), is there any efficient way to throw away the value attached to a std::future<T> and be left only with the underlying std::future<void> representing the event's completion?
Something like the following could work but would be potentially inefficient:
auto f = api_a();
f.wait();
auto void_f = std::async(std::launch::defer, []{});
api_b(void_f);
The best you can get is probably this:
auto f = api_a();
auto void_f = std::async(std::launch::deferred,[fut = std::move(f)]{ fut.wait();});
api_b(void_f);
template<class U>
struct convert_future_t {
template<class T>
std::future<U> operator()( std::future<T>&& f ) const {
return std::async(std::launch::deferred,
[f=std::move(f)]()->U{ return f.get(); }
);
}
}
template<>
struct convert_future_t<void> {
template<class T>
std::future<void> operator()( std::future<T>&& f ) const {
return std::async(std::launch::deferred,
[f=std::move(f)]()->void{ f.get(); }
);
}
}
template<class U, class T>
std::future<U> convert_future( std::future<T>&& f ) {
return convert_future_t<U>{}(std::move(f));
}
this is a generic version of #sbabbi's answer.
api_b( convert_future<void>( api_a() ) );
that allows for any target and dest type to work transparently.
The large downside to this approach is that the resulting future is a deferred future wrapping a (possibly async) future, which means that .wait_for() and .ready() APIs do not work like async futures do. The returned future will never be ready until waited.
So we can improve this marginally:
template<class T>
struct ready_future_t {
template<class...Us>
std::future<T> operator()( Us&&...us ) const {
std::promise<T> p;
p.set_value(T(std::forward<Us>(us)...));
return p.get_future();
}
};
template<>
struct ready_future_t<void> {
using T=void;
// throws away the Us&&...s
template<class...Us>
std::future<T> operator()( Us&&...us ) const {
std::promise<T> p;
p.set_value();
return p.get_future();
}
};
template<class T, class...Us>
std::future<T> ready_future(Us&&...us){
return ready_future_t<T>{}(std::forward<Us>(us)...);
}
template<class U>
struct convert_future_t {
template<class T>
std::future<U> operator()( std::future<T>&& f ) const {
if (f.wait_for(0ms)==std::future_status::ready)
return ready_future<U>(f.get());
return std::async(std::launch::deferred,
[f=std::move(f)]()->U{ return f.get(); }
);
}
};
template<>
struct convert_future_t<void> {
template<class T>
std::future<void> operator()( std::future<T>&& f ) const {
if (f.wait_for(0ms)==std::future_status::ready)
return ready_future<void>();
return std::async(std::launch::deferred,
[f=std::move(f)]()->void{ f.get(); }
);
}
};
where at least if the future was already ready by the time we converted it, the returned future is also ready.
live example