issues with const correctness using boost::fusion::map - c++

I'm writing some classes that use boost::fusion::map. Bellow you find a simplified code:
template <typename ObjDef>
struct Object
{
typedef
typename
boost::fusion::result_of::as_map<valid_list_of_fusion_pairs>::type map_type;
map_type map;
Object()
: map()
{}
Object(Object const & other)
: map(other.map)
{}
Object & operator=(Object const & other)
{
map = other.map;
return *this;
}
// non-const version
template <typename FieldId>
typename
boost::fusion::result_of::at_key<map_type, FieldId>::type get()
{
return boost::fusion::at_key<FieldId>(map);
}
// const version
template <typename FieldId>
typename
boost::fusion::result_of::at_key<map_type const, FieldId>::type get() const
{
return boost::fusion::at_key<FieldId>(map);
}
};
and another class:
template <typename Obj, typename FieldId>
class Field
{
private:
Obj &obj_m;
public:
// type returned by \c operator()
typedef
typename
boost::fusion::result_of::at_key<typename Obj::map_type, FieldId>::type return_type;
// type returned by \c operator() const
typedef
typename
boost::fusion::result_of::at_key<typename Obj::map_type const, FieldId>::type return_type_const;
Field(Obj &obj)
: obj_m(obj)
{ }
virtual ~Field()
{ }
return_type operator()()
{
return obj_m.template get<FieldId>();
}
return_type_const operator()() const
{
/*
* PROBLEM!
*/
Obj const & obj_const = obj_m;
return obj_const.template get<FieldId>();
}
};
Look for "PROBLEM!" in the comments in the above code. In that method, the compiler ignores the const qualifier of the method and calls the non-const version of obj_m.get() allowing to do something like:
obj_m.template get<FieldId>() = 10;
which is not correct since this method is const! Then, to force the compiler to call the const version, a const reference to obj_m is declared. Now the sentence
obj_const.template get<FieldId>() = 0;
produces a compilation error. So far this is not a problem for the current method,but it is not convenient for const correctness and it is definitively undesired
any idea why is this happening?
thanks!

Related

How to forward a call to a member function template that can be const or non const depending on the template type?

I have something similar to this (stripped down example to the relevant points)
struct Foo
{
template <typename T>
constexpr std::enable_if<someTrait<T>::value ,T>::type& get() const { return something(); }
template <typename T>
std::enable_if<someOtherTrait<T>::value ,T>::type& get() { return somethingDifferent(); }
class Nested
{
public:
template <typename T>
T& get() { return foo.get<T>(); }
private:
Foo& foo;
}
}
e.g. Foo::get evaluates to a const constexpr function or something completely non-const depending on the template type.
Now I want to be able to do this
class Bar : public Foo::Nested
{
void nonConstFn()
{
auto& a = get<TypeA>();
//...
}
void constFn() const // <===== Won't compile
{
auto& a = get<TypeA>();
//...
}
}
It's obvious that Bar::constFn won't compile as it calls the non-const function Foo::Nested::get<TypeA> – even if TypeA would satisfy someTrait and call the const function constexpr Foo::get<TypeA>() const again in the end.
Leaving the constexpr aside for now, how do I propagate the constness of the called function in my nested class' function template? I tried simply overloading it with a const and non-const version of Nested::get which solves it for clang on macOS but fails with MSVC in Visual Studio 2015 on Windows, which is unfortunately a required build target.
Note that the original example contains a lot more than just two versions of Foo::get so I'd like to avoid repeating all versions in Foo::Nested but forward it with one or two function templates if possible
Edit: I tried the proposal to use
template <typename T>
constexpr auto get() const -> decltype(foo.get<T>()) { return foo.get<T>(); }
template <typename T>
constexpr auto get() -> decltype(foo.get<T>()) { return foo.get<T>(); }
on godbolt.org which seems to compile fine for current MSVC versions but fails with Visual Studio 2015 MSVC 19.0, so this is no option
First of you need enable_if::type for the SFINAE to work.
To get to your question you need to overload Nested::get:
#include <type_traits>
struct Foo
{
template <typename T>
constexpr std::enable_if_t<std::is_integral_v<T>, T>&
get() const
{ return something(); }
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>&
get()
{ return somethingDifferent(); }
int& something() const;
float& somethingDifferent();
class Nested
{
public:
Nested();
template <typename T>
constexpr std::enable_if_t<std::is_integral_v<T>, T>&
get() const { return foo.get<T>(); }
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>&
get() { return foo.get<T>(); }
private:
Foo& foo;
};
};
class Bar : public Foo::Nested
{
void nonConstFn()
{
[[maybe_unused]] auto& a = get<int>();
[[maybe_unused]] auto& b = get<float>();
}
void constFn() const
{
[[maybe_unused]] auto& a = get<int>();
}
};
You need const and non-const overload in Nested, you might avoid to repeat all overload/SFINAE with another (simple) SFINAE:
class Nested
{
Foo& foo; // Should be declared before the decltype usage
public:
Nested();
template <typename T>
constexpr auto get() const -> (decltype(foo.get<T>())) { return foo.get<T>(); }
template <typename T>
constexpr auto get() -> (decltype(foo.get<T>())) { return foo.get<T>(); }
};
Consider the following problem, which is meaningless but proposes a solution to yours. You have a class with two functions and an invoker for them
class A
{
public: void foo() { printf("foo"); }
public: void foo() const { printf("foo const"); }
public: void invoke() { foo(); }
}
If you do A().invoke(), you will get foo obviously. If you want to force to execute the const type function, how do you achieve that? OK, you make the following change
A::invoke() { const_cast<const A*>(this)->foo(); } and that's it.

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.

C++ Conditional Templates Compilation based on data type

I was really hoping I could achieve this using C++ (11) Templates, but I'm facing some problem here. So we have a custom pointer object which internally could be of any of these types: a list of objects of its own type/an int/a char/bool/long/double/char* or any other primitive type, and it's decided by a flag that this object stores. There are global methods to get values of specific types from this object.
Now, my purpose is simple. I know that for my case, my object is a list of such objects, so I wanted to write a function like this as it's a common scenario:
template <typename T>
std::vector<T> List_To_Vector(Object& list)
{
std::vector<T> vec;
int listSize = Func_Size(list);
for (int i = 0; i < listSize; ++i)
{
//let's say this function gives list items one by one
Object arg = Func_Next(list);
if (std::is_same<T, int>::value || std::is_same<T, unsigned int>::value)
vec.push_back((T)Func_IntValue(arg));
else if (std::is_same<T, float>::value || std::is_same<T, double>::value)
vec.push_back((T)Func_DoubleValue(arg));
else if (std::is_same<T, std::string>::value || std::is_same<T, char*>::value)
vec.push_back((T)Func_StringValue(arg)); //Func_StringValue returns char*, so conversion to std::string should work
else if (std::is_same<T, bool>::value)
vec.push_back(Func_BoolValue(arg));
else if (std::is_same<T, char>::value)
vec.push_back(Func_CharValue(arg));
vec.push_back(val);
}
return vec;
}
int main()
{
Object listContainingStrings = GetListOfNames();
Object listContainingNumbers = GetListOfNumbers();
std::vector<string> vec1 = List_To_STD_Vector<string>(listContainingStrings);
std::vector<int> vec2 = List_To_STD_Vector<int>(listContainingNumbers);
return 0;
}
The problem is, C++ complains here as it tries to compile the code taking T = std::string, and int to string or float to string conversions would fail. What I really wanted here was a way to compile the int part of the code when the type is detected as int, and not of any other type.
I can use Template function specialization or overloading, but then I think it really defeats the purpose of templates here and I could just write 8 different functions for 8 different types (e.g. List_To_String_Vector, List_To_Int_Vector and so on).
I also tried another hack, using reinterpret_cast<T*> on the address of the each return types, and then dereferencing it to add to the vector. That kind of worked, but has Compiler warnings and I think that's undefined behavior.
Is there a way to make this work properly?
Thanks!
The fundamental theorem of software engineering:
We can solve any problem by introducing an extra level of indirection.
List_To_Vector is doing too much – both conversion from Object to T, and filling a vector; abstract out the former and the solution becomes natural. First, List_To_Vector:
template<typename T>
std::vector<T> List_To_Vector(Object& list) {
std::vector<T> vec;
for (int i = 0, listSize = Func_Size(list); i < listSize; ++i) {
vec.push_back(Object_To<T>(Func_Next(list)));
}
return vec;
}
Now you can just overload or specialize Object_To as necessary. Here's one way, using SFINAE:
// not strictly necessary, but reduces noise a bit
template<bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template<typename T>
auto Object_To(Object arg)
-> enable_if_t<std::is_same<T, int>{} || std::is_same<T, unsigned>{}, T>
{
return (T)Func_IntValue(arg);
}
template<typename T>
auto Object_To(Object arg)
-> enable_if_t<std::is_same<T, float>{} || std::is_same<T, double>{}, T>
{
return (T)Func_DoubleValue(arg);
}
template<typename T>
auto Object_To(Object arg)
-> enable_if_t<std::is_same<T, std::string>{} || std::is_same<T, char*>{}, T>
{
return (T)Func_StringValue(arg);
}
template<typename T>
auto Object_To(Object arg) -> enable_if_t<std::is_same<T, bool>{}, T>
{
return Func_BoolValue(arg);
}
template<typename T>
auto Object_To(Object arg) -> enable_if_t<std::is_same<T, char>{}, T>
{
return Func_CharValue(arg);
}
Using something like boost::fusion::map<> can make this much cleaner if you can afford the dependency.
Let's act one level below your List_To_Vector function. The issue I see is that you have a collection of unrelated Func_*Value functions, so let's gather them under a single, type-aware template once and for all:
template <class>
struct valueGetter;
template <> struct valueGetter<float> { static constexpr auto &get = Func_DoubleValue; };
template <> struct valueGetter<double> { static constexpr auto &get = Func_DoubleValue; };
template <> struct valueGetter<int> { static constexpr auto &get = Func_IntValue; };
// etc.
Now List_To_Vector becomes trivial:
template <typename T>
std::vector<T> List_To_Vector(Object& list)
{
std::vector<T> vec;
int listSize = Func_Size(list);
for (int i = 0; i < listSize; ++i)
vec.push_back(valueGetter<T>::get(Func_Next(list)));
return vec;
}
See it live on Coliru
Can I play too?
I propose a solution based on a template deleted convertion function
template <typename T>
T getTValue (T const &, Object const &) = delete;
and some not-template conversion functions, with the same signature, for calling the right Func_X_Value() function; something like
int getTValue (int const &, Object const & obj)
{ return Func_IntValue(arg); }
unsigned int getTValue (unsigned int const &, Object const & obj)
{ return Func_IntValue(arg); }
float getTValue (float const &, Object const & obj)
{ return Func_DoubleValue(arg); }
double getTValue (double const &, Object const & obj)
{ return Func_DoubleValue(arg); }
char * getTValue (char const * &, Object const & obj)
{ return Func_StringValue(arg); }
std::string getTValue (std::string const &, Object const & obj)
{ return Func_StringValue(arg); }
char getTValue (char const &, Object const & obj)
{ return Func_CharValue(arg); }
bool getTValue (bool const &, Object const & obj)
{ return Func_BoolValue(arg); }
The first argument is unused and is introduced only to select the right not-template functions, so the for cycle become
for (int i = 0; i < listSize; ++i)
vec.push_back(getTValue(T(), arg));
The template deleted function is introduced to avoid unwanted type conversions (by example: from short int to int) and impose an error, in compilation phase, if someone try to call List_To_Vector() with a wrong T.
So, by example, call
std::vector<int> vi = List_To_Vector<int>(listContainingNumbers);
should be OK but call
std::vector<long> vl = List_To_Vector<long>(listContainingNumbers);
because getTValue<long>() is deleted and there isn't a getTValue(long const &, Object const &) not-template function.
p.s.: cautions: code not tested.
I suggest using a helper to deduce correct overload for conversion:
class convert
{
const Object& from;
public:
explicit convert(const Object& from): from(from) {}
operator char() const { return Func_CharValue(from); }
operator bool() const { return Func_BoolValue(from); }
operator std::string() const { return Func_StringValue(from); }
operator const char*() const { return Func_StringValue(from); }
// ...
};
// ...
vec.push_back(convert(arg));
No need for templates.
This does have a drawback of having to repeat each concrete type even if they use the same conversion function. But you don't have terribly many of those. The overloads could be augmented with a template conversion operator that is disabled by default, but enabled for the types that reuse a common conversion function.
I would suggest using function specialisations to wrap each call, that way you can have precise control on whats happens for each type e.g.
template<typename T> T object_to(const Object& arg) { }
template<> int object_to(const Object& arg) { return Func_IntValue(arg); }
template<> unsigned int object_to(const Object& arg) { return Func_IntValue(arg); }
template<> std::string object_to(const Object& arg) { return Func_StringValue(arg); }
template<> float object_to(const Object& arg) { return Func_DoubleValue(arg); }
template<> double object_to(const Object& arg) { return Func_DoubleValue(arg); }
template<> bool object_to(const Object& arg) { return Func_BoolValue(arg); }
template<> char object_to(const Object& arg) { return Func_CharValue(arg); }
then give your Object class some standard algorithm methods and plug it into the following:
template<typename T>
std::vector<T> to_vector(const object_list& obj_list) {
std::vector<T> vec(obj_list.size());
std::transform(obj_list.begin(),obj_list.end(),vec.begin(),[](const Object& obj) {
return object_to<T>(obj);
});
return vec;
}

Restrict functor parameter type and constness

I am trying to implement a resource protection class which would combine data along with a shared mutex (actually, QReadWriteLock, but it's similar). The class must provide the method to apply a user-defined function to the data when the lock is acquired. I would like this apply method to work differently depending on the function parameter (reference, const reference, or value). For example, when the user passes a function like int (const DataType &) it shouldn't block exclusively as we are just reading the data and, conversely, when the function has the signature like void (DataType &) that implies data modification, hence the exclusive lock is needed.
My first attempt was to use std::function:
template <typename T>
class Resource1
{
public:
template <typename Result>
Result apply(std::function<Result(T &)> &&f)
{
QWriteLocker locker(&this->lock); // acquire exclusive lock
return std::forward<std::function<Result(T &)>>(f)(this->data);
}
template <typename Result>
Result apply(std::function<Result(const T &)> &&f) const
{
QReadLocker locker(&this->lock); // acquire shared lock
return std::forward<std::function<Result (const T &)>>(f)(this->data);
}
private:
T data;
mutable QReadWriteLock lock;
};
But std::function doesn't seem to restrict parameter constness, so std::function<void (int &)> can easily accept void (const int &), which is not what I want. Also in this case it can't deduce lambda's result type, so I have to specify it manually:
Resource1<QList<int>> resource1;
resource1.apply<void>([](QList<int> &lst) { lst.append(11); }); // calls non-const version (ok)
resource1.apply<int>([](const QList<int> &lst) -> int { return lst.size(); }); // also calls non-const version (wrong)
My second attempt was to use std::result_of and return type SFINAE:
template <typename T>
class Resource2
{
public:
template <typename F>
typename std::result_of<F (T &)>::type apply(F &&f)
{
QWriteLocker locker(&this->lock); // lock exclusively
return std::forward<F>(f)(this->data);
}
template <typename F>
typename std::result_of<F (const T &)>::type apply(F &&f) const
{
QReadLocker locker(&this->lock); // lock non-exclusively
return std::forward<F>(f)(this->data);
}
private:
T data;
mutable QReadWriteLock lock;
};
Resource2<QList<int>> resource2;
resource2.apply([](QList<int> &lst) {lst.append(12); }); // calls non-const version (ok)
resource2.apply([](const QList<int> &lst) { return lst.size(); }); // also calls non-const version (wrong)
Mainly the same thing happens: as long as the object is non-const the mutable version of apply gets called and result_of doesn't restrict anything.
Is there any way to achieve this?
You may do the following
template <std::size_t N>
struct overload_priority : overload_priority<N - 1> {};
template <> struct overload_priority<0> {};
using low_priority = overload_priority<0>;
using high_priority = overload_priority<1>;
template <typename T>
class Resource
{
public:
template <typename F>
auto apply(F&& f) const
// -> decltype(apply_impl(std::forward<F>(f), high_priority{}))
{
return apply_impl(std::forward<F>(f), high_priority{});
}
template <typename F>
auto apply(F&& f)
// -> decltype(apply_impl(std::forward<F>(f), high_priority{}))
{
return apply_impl(std::forward<F>(f), high_priority{});
}
private:
template <typename F>
auto apply_impl(F&& f, low_priority) -> decltype(f(std::declval<T&>()))
{
std::cout << "ReadLock\n";
return std::forward<F>(f)(this->data);
}
template <typename F>
auto apply_impl(F&& f, high_priority) -> decltype(f(std::declval<const T&>())) const
{
std::cout << "WriteLock\n";
return std::forward<F>(f)(this->data);
}
private:
T data;
};
Demo
Jarod has given a workaround, but I'll explain why you cannot achieve that this regular way.
The problem is that:
Overload resolution prefers non-const member functions over const member functions when called from a non-const object
whatever object this signature void foo(A&) can accept, void foo(const A&) can also the same object. The latter even has a broader binding set than the former.
Hence, to solve it, you will have to at least defeat point 1 before getting to 2. As Jarod has done.
From your signatures (see my comment annotations):
template <typename F>
typename std::result_of<F (T &)>::type apply(F &&f) //non-const member function
{
return std::forward<F>(f)(this->data);
}
template <typename F>
typename std::result_of<F (const T &)>::type apply(F &&f) const //const member function
{
return std::forward<F>(f)(this->data);
}
When you call it like:
resource2.apply([](QList<int> &lst) {lst.append(12); }); //1
resource2.apply([](const QList<int> &lst) { return lst.size(); }); //2
First of all, remember that resource2 isn't a const reference. Hence, the non-const membr function of apply will always be prefered by Overload resolution.
Now, taking the case of the first call //1, Whatever that lambda is callable with, then then the second one is also callable with that object
A simplified mock-up of what you are trying to do is:
struct A{
template<typename Func>
void foo(Func&& f); //enable if we can call f(B&);
template<typename Func>
void foo(Func&& f) const; //enable if we can call f(const B&);
};
void bar1(B&);
void bar2(const B&);
int main(){
A a;
a.foo(bar1);
a.foo(bar2);
//bar1 and bar2 can be both called with lvalues
B b;
bar1(b);
bar2(b);
}
As I understand it, you want to discriminate a parameter that's a std::function that takes a const reference versus a non-constant reference.
The following SFINAE-based approach seems to work, using a helper specialization class:
#include <functional>
#include <iostream>
template<typename ...Args>
using void_t=void;
template<typename Result,
typename T,
typename lambda,
typename void_t=void> class apply_helper;
template <typename T>
class Resource1
{
public:
template <typename Result, typename lambda>
Result apply(lambda &&l)
{
return apply_helper<Result, T, lambda>::helper(std::forward<lambda>(l));
}
};
template<typename Result, typename T, typename lambda, typename void_t>
class apply_helper {
public:
static Result helper(lambda &&l)
{
std::cout << "T &" << std::endl;
T t;
return l(t);
}
};
template<typename Result, typename T, typename lambda>
class apply_helper<Result, T, lambda,
void_t<decltype( std::declval<lambda>()( std::declval<T>()))>> {
public:
static Result helper(lambda &&l)
{
std::cout << "const T &" << std::endl;
return l( T());
}
};
Resource1<int> test;
int main()
{
auto lambda1=std::function<char (const int &)>([](const int &i)
{
return (char)i;
});
auto lambda2=std::function<char (int &)>([](int &i)
{
return (char)i;
});
auto lambda3=[](const int &i) { return (char)i; };
auto lambda4=[](int &i) { return (char)i; };
test.apply<char>(lambda1);
test.apply<char>(lambda2);
test.apply<char>(lambda3);
test.apply<char>(lambda4);
}
Output:
const T &
T &
const T &
T &
Demo
The helper() static class in the specialized class can now be modified to take a this parameter, instead, and then use it to trampoline back into the original template's class's method.
As long as the capture lists of your lambdas are empty, you can rely on the fact that such a lambda decays to a function pointer.
It's suffice to discriminate between the two types.
It follows a minimal, working example:
#include<iostream>
template <typename T>
class Resource {
public:
template <typename Result>
Result apply(Result(*f)(T &)) {
std::cout << "non-const" << std::endl;
return f(this->data);
}
template <typename Result>
Result apply(Result(*f)(const T &)) const {
std::cout << "const" << std::endl;
return f(this->data);
}
private:
T data;
};
int main() {
Resource<int> resource;
resource.apply<void>([](int &lst) { });
resource.apply<int>([](const int &lst) -> int { return 42; });
}

C++: Optimize using templates variables

Currently, I have some code as follows
template<typename Type>
Type* getValue(std::string name, bool tryUseGetter = true)
{
if(tryUseGetter)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
else
{
return (Type*)_properties[name]->data;
}
}
Is there a way to make tryUseGetter a compile time switch? i.e. move it to the template declaration so it's something akin to this
template<typename Type, bool tryUseGetter = true>
...
Thanks.
As an alternative to Dirk's answer, you can put the function in a struct. Template classes can be partially specialized (in contrast to template functions), so you can write:
template<typename Type, bool tryUseGetter = true>
struct getValue;
template<typename Type>
struct getValue<Type, true>
{
Type* run(std::string name)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
};
template<typename Type>
struct getValue<Type, false>
{
Type* run(std::string name)
{
return (Type*)_properties[name]->data;
}
};
Call it as getValue<T>::run("foo") or getValue<T, false>::run("foo") .
I'm not 100% certain that it's allowed to have template parameters of the type bool, so perhaps you should change it to int.
You can get compile-time dispatch of the "try-use-getter" stuff by splitting your method into two and having the compiler dispatch to the appropriate method:
struct __try_use_getter { }
external const __try_use_getter tryusegetter;
template<typename Type>
Type*
getValue(std::string name, const __try_use_getter&)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
template<typename Type>
Type*
getValue(std::string name)
{
return (Type*)_properties[name]->data;
}
With this scenario in place, you would have full compile-time dispatching:
int result = getValue("foo", tryusegetter);
would try the getter first, whereas
int result = getValue("foo");
would immediately call the getter-less version.
Just in case you really need it (although from a performance point of view, i doubt it would be noticeable), i would overload
template<typename Type>
Type* getValue(std::string const &name)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
template<typename Type, bool tryUseGetter>
Type *getValue(std::string const &name)
{
if(tryUseGetter)
{
return getValue<Type>(name);
}
else
{
return (Type*)_properties[name]->data;
}
}
Also, you should first follow the real rules: Pass name by-const-reference instead of passing a copy, for example.
You could use type cast operator and structure getValue as follows (usage syntax will be the same as with function) :
template<typename Type, bool tryUseGetter = true>
struct getValue {};
template<typename Type>
struct getValue<Type, true> {
getValue(const std::string& name) : name(name) {};
operator Type*() const {
if(_properties[name]->hasGetter) {
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
private:
const std::string& name;
};
template<typename Type>
struct getValue<Type, false> {
getValue(const std::string& name) : name(name) {};
operator Type*() const {
return (Type*)_properties[name]->data;
}
private:
const std::string& name;
};
Usage:
int main () {
int* i = getValue<int>( "TEST" ); // true by default
Xstruct* x = getValue<Xstruct, false>( "XS" ); // false
}
Before you go and make the code all complicated...did you check to see if the optimizing compiler was already doing this for you?