I have come across code like
bool open_resource(..., shared_ptr<resource> & res)
{
...
shared_ptr<resource> newResource(new resource(...));
res = move(newResource);
return true;
}
which is then called with
shared_ptr<resource> res;
open_resource(..., res);
and then, as far as I saw, res is NOT used in ways that require sharing the pointer.
Of course I immediately thought of changing
shared_ptr<resource> newResource(new resource(...));
res = move(newResource);
with
res = make_shared<resource>(...)
...but then I hit a roadblock. Now I can no longer advise to change the shared_ptr reference to something more basic; at least not if I want to ensure that, if the caller actually needs a shared_ptr later, the control block efficiently resides on the same allocation as the object. For this to work, it must be a shared_ptr from the beginning.
On the other side, shared_ptr is a "heavy" type; it has two counters and aliasing and all kinds of features that really seem unneeded in most calling sites. And yet if it is shared_ptr in the signature, that they have to use.
The best solution I see is to move the body of the function to a helper function, and then overload.
bool get_resource_parameters(Param1& param1,..., ParamN& paramN)
{
...
}
bool open_resource(..., shared_ptr<resource> & res)
{
Param1 param1;
...
ParamN paramN;
if(!get_resource_parameters(param1,...,paramN))
return false;
res = make_shared<resource>(param1,...,paramN);
return true;
}
bool open_resource(..., unique_ptr<resource> & res)
{
Param1 param1;
...
ParamN paramN;
if(!get_resource_parameters(param1,...,paramN))
return false;
res = unique_ptr<resource>(new resource(param1,...,paramN));
return true;
}
But it's really not satisfying.
Does anyone see a better, more C++ solution?
Edit
Yes, the C++ way would be to return the pointer rather than a bool (and check for null). I cannot overload for shared_ptr in this case, but I can then assign the unique_ptr temporary returned to a shared_ptr varaible, and the appropriate constructor will convert it.
However, this way I lose the single allocation of make_shared. can I save it?
std::shared_ptr has a converting constructor from std::unique_ptr. Why don't you make the function return a std::unique_ptr by value:
unique_ptr<resource> open_resource(...);
This also serves as documentation that this is a factory function that transfers the ownership of the resource to the caller.
And let the caller decide how they want it:
auto x = open_resource(...);
// or
std::shared_ptr<resource> x{open_resource(...)};
To allow unique_ptr/shared_ptr, you may use template:
// Dispatcher for make_unique/make_shared
template <template <typename...> class Ptr, typename T>
struct make_helper;
template <typename T>
struct make_helper<std::unique_ptr, T>
{
template <typename ...Ts>
std::unique_ptr<T> operator() (Ts&&... args) const {
return std::make_unique<T>(std::forward<Ts>(args)...);
}
};
template <typename T>
struct make_helper<std::shared_ptr, T>
{
template <typename ...Ts>
std::shared_ptr<T> operator() (Ts&&... args) const {
return std::make_shared<T>(std::forward<Ts>(args)...);
}
};
template <template <typename...> class Ptr, typename T, typename ... Ts>
auto make(Ts&&... args)
{
return make_helper<Ptr, T>{}(std::forward<Ts>(args)...);
}
And then
bool get_resource_parameters(Param1& param1,..., ParamN& paramN)
{
//...
}
template <template <typename...> class Ptr>
Ptr<resource> open_resource(...)
{
Param1 param1;
...
ParamN paramN;
if(!get_resource_parameters(param1, ..., paramN))
return nullptr;
return = make<Ptr, resource>(param1, ..., paramN);
}
And check for nullptr instead of split bool and smart_pointer.
Related
I've been trying to expand a non value parameter pack recently in C++. Is this possible? And if it's not, why?
I mean, as you can see, in the line with the comment //, given a parameter pack for the TypeMap class, how can I call addType<T>() with each type of the parameter pack? Thanks in advance!
template <typename... T>
class TypeMap
{
using vari_cmps = std::variant<T*...>;
private:
template<typename Type>
void addType()
{
typemap[typeid(Type).name()] = std::make_unique<Type>(0).get();
}
public:
std::map<const char*, vari_cmps> typemap{};
TypeMap()
{
(addType<T,...>()); // Idk how to use this in order to make it work
}
~TypeMap()
{
typemap.clear();
}
};
As #HolyBlackCat has already answered in the comments, you can expand it like this:
TypeMap() {
(addType<T>(), ...);
}
If T is std::string, int, float this would expand to:
TypeMap() {
(addType<std::string>(), addType<int>(), addType<float>());
}
There are however a few more issues in this code-snippet:
1. addType()
addType() will not work as you'd expect, due to the unique_ptr deleteing your object after you put it into the map.
.get() only retrieves the pointer that the unique_ptr manages but does not transfer ownership, so the unique_ptr will still delete the pointed-to object once it gets out of scope, leaving a dangling pointer in your map.
so your addType() is roughly equivalent to:
template<typename Type>
void addType() {
Type* tptr = new Type(0); // unique pointer constructs object
typemap[typeid(Type).name()] = tptr; // insert pointer value of unique pointer
delete tptr; // unique pointer destructs
}
You could fix this by releasing the unique_ptr after inserting its value into the map & then cleaning it up in the destructor:
template<typename Type>
void addType() {
auto ptr = std::make_unique<Type>(0);
typemap[typeid(Type).name()] = ptr.get();
ptr.release(); // now unique_ptr won't delete the object
}
~TypeMap() {
// cleanup all pointers
for(auto& [name, ptrVariant] : typemap)
std::visit([](auto ptr) { delete ptr; }, ptrVariant);
}
2. Consider using std::type_index instead of const char* as map key
std::type_info::name() returns an implementation-defined name for the given type, so you have no guarantee that you will get an unique name for a given type.
Returns an implementation defined null-terminated character string containing the name of the type. No guarantees are given; in particular, the returned string can be identical for several types and change between invocations of the same program.
std::type_index on the other hand is build specifically for this purpose - using types as keys - and comes with all comparison operators & a std::hash specialization, so you can use it with std::map & std::unordered_map out of the box.
e.g.:
template <class... T>
class TypeMap
{
using vari_cmps = std::variant<T*...>;
private:
template<typename Type>
void addType()
{
typemap[std::type_index(typeid(Type))] = /* something */;
}
public:
std::map<std::type_index, vari_cmps> typemap{};
TypeMap() { /* ... */ }
~TypeMap() { /* ... */ }
template<class U>
U* get() {
auto it = typemap.find(std::type_index(typeid(U)));
return std::get<U*>(it->second);
}
};
Consider using std::tuple
std::tuple is basically built for this task, storing a list of arbitrary types:
e.g.:
template <class... T>
class TypeMap
{
private:
std::tuple<std::unique_ptr<T>...> values;
public:
TypeMap() : values(std::make_unique<T>(0)...) {
}
template<class U> requires (std::is_same_v<U, T> || ...)
U& get() { return *std::get<std::unique_ptr<U>>(values); }
template<class U> requires (std::is_same_v<U, T> || ...)
U const& get() const { return *std::get<std::unique_ptr<U>>(values); }
};
usage:
TypeMap<int, double, float> tm;
tm.get<int>() = 12;
If you want you can also store T's directly in the tuple, avoiding the additional allocations.
I am trying to implement a pointer to member function wrapper where the return type and parameter types are known but the class type of the member function is not known. This is for a C++ project targeting resource constrained (No heap allocation/c++ standard library) microprocessor.
The following code seems to work (you can run it HERE) and it fulfills our general requirements, but it uses reinterpret_cast hackery.
//can't use any c++ std libs or heap allocation
#include <cstdio>
template<typename Ret,typename... Args>
struct member_cb
{
template<typename T>
void set_cb(T *obj_,Ret (T::*func)(Args...))
{
obj = reinterpret_cast<member_cb*>(obj_);
cb = reinterpret_cast<Ret (member_cb::*)(Args...)>(func);
}
Ret operator()(Args... num)
{
return (obj->*cb)(num...);
}
member_cb* obj;
Ret (member_cb::*cb)(Args...);
};
struct Bar{
void someFunc(int n2){
printf("someFunc called with parameter: %d\n",n2);
}
};
int main()
{
//class type of Bar is not known at wrapper creation
member_cb<void,int> foo;
Bar bar;
foo.set_cb(&bar, &Bar::someFunc);
foo(42);
}
I want to do this without the reinterpret_cast. I believe there is a solution using a lambda that is created by the set_cb() function something like this:
template<typename Ret,typename... Args>
struct member_cb
{
template<typename T>
void set_cb(T *obj_,Ret (T::*func)(Args...))
{
cb_func = [=](Args...num)
{
(obj_->*func)(num...);
};
}
Ret operator()(Args... args)
{
return cb_func(args...);
}
Ret (*cb_func)(Args...);
}
The above code will not compile (you can try it HERE). Problem is that the regular function pointers like cb_func can only point to lambdas that have no captures, and the lambda has to capture the obj_ and the func parameters. Any suggestions on making this work would be appreciated.
A simple, compiler-independent solution:
template <typename Signature>
struct member_cb;
template <typename Ret, typename... Args>
struct member_cb<Ret(Args...)>
{
template <typename T, Ret (T::*func)(Args...)>
static Ret wrapper(void *object, Args&&... args) {
T *o = reinterpret_cast<T *>(object);
return (o->*func)(std::forward<Args>(args)...);
}
template <typename T, Ret (T::*func)(Args...)>
void set_cb(T *obj_)
{
obj = obj_;
cb_func = wrapper<T, func>;
}
// since C++17:
template <auto func, typename T>
void set_cb(T *obj_)
{
obj = obj_;
cb_func = wrapper<T, func>;
}
Ret operator() (Args&& ...args)
{
return cb_func(obj, std::forward<Args>(args)...);
}
void *obj;
Ret (*cb_func)(void *, Args&&...);
};
...
member_cb<void(int)> foo;
foo.set_cb<Bar, &Bar::someFunc>(&bar);
foo.set_cb<&Bar::someFunc>(&bar); // since C++17
The key limitation is that someFunc must be known at compile-time at the place set_cb is called, so you can’t take arbitrary method pointer and convert it to a member_cb. It is possible to change the object keeping the method pointer intact, though (but that’s not type-safe).
Another possible problem is that the compiler may need to emit a wrapper instance for each and every method that is ever used as a callback.
The upside is that it should work on any C++11-compliant compiler (C++17 for nicer syntax), and member_cb itself is small.
std::deque<std::function<std::string()>> log_queue;
void store_log(T&& t, U&&... u) const
{
log_queue.push_back(
[t, u...]() {
return format_log(t, u...));
});
if (log_queue.size() > 1000)
{
log_queue.pop_front();
}
}
I use the above function to store the latest 1000 log messages in a circular buffer and print the contents of log_queue when an issue happens in my developing environment.
There is a problem with this approach. Some of the arguments (U...) are pointer wrappers.
So when I print log_queue contents, I see the last updated value for these pointers instead of the value it had when the store_log function was called. I can solve this issue by storing std::string instead of the lambda, but that is very very expensive (I want to stringify only the last 1000 logs). So instead I would like to store the value contained by the pointer wrappers
instead of the pointer wrapper itself. Is there any easy way?
Pointer wrapper details:
template <typename T>
class ptr_wrapper
{
T* t = nullptr;
int ref_count = 0;
// constructors and destructors
// functions for updating ref_count whenevr this object is copies/moved etc
};
};
You might apply transformation before the capture:
void store_log(T&& t, Us&&... us) const
{
log_queue.push_back(
[tup = std::make_tuple(value(t), value(us)...)]() {
return std::apply([](const auto&... args){ format_log(args...), tup));
});
if (log_queue.size() > 1000)
{
log_queue.pop_front();
}
}
with
template <typename T>
const T& value(const T& value) { return value; }
template <typename T>
std::optional<T> value(const ptr_wrapper<T>& wrapper) {
if (wrapper.t) return *wrapper.t;
return {};
}
// other overloads possible to do deep copy, instead of keeping reference
// ...
C++14's syntax; in C++11, you have to declare the variable before the lambda.
I'm making a class template to encode function pointers. The function can have any result type and number / type of parameters. This is what I have:
LPVOID EncodePtr(LPVOID ptr) {
// Encode...
return ptr;
}
LPVOID DecodePtr(LPVOID ptr) {
// Decode...
return ptr;
}
template<class T>
class encoded_ptr {
public:
typedef encoded_ptr<T> _Myt;
encoded_ptr() {
ptr_ = (T*)EncodePtr(nullptr);
}
// Irresponsible?
template<class _OtherType>
encoded_ptr(_OtherType ptr) {
ptr_ = (T*)DecodePtr((LPVOID)ptr);
}
~encoded_ptr() {
ptr_ = (T*)EncodePtr(nullptr);
}
// Makes it possible to call the function directly
template<class... _Args>
typename std::result_of<T*(_Args...)>::type operator()(_Args... _Ax) {
T* fn = get();
return fn(_Ax...);
}
T* get() const {
return (T*)DecodePtr((LPVOID)ptr_);
}
bool is_set() {
return (get() != nullptr);
}
private:
T* ptr_;
};
It works as expected. Eg.:
encoded_ptr<decltype(MessageBoxA)> MsgBox;
MsgBox = &MessageBoxA; // Could also initialize in the constructor
// (HWND)0 is justified by the actual problem in the question
MsgBox((HWND)0, "Test message!", "Test", 0);
The first problem is that the way the parenthesis operator () is declared doesn't allow Visual Studio's IntelliSense to make its magic and give me hints about the function parameters:
template<class... _Args>
typename std::result_of<T*(_Args...)>::type operator()(_Args... _Ax) {
T* fn = get();
return fn(_Ax...);
}
Instead of using (_Args... _Ax), I'd like to unpack the actual function parameters so that IntelliSense can give hints correctly.
Current behaviour is:
Expected behaviour is:
The second problem is that calling the function this way, the compiler doesn't do basic casts, forcing me to cast NULL to (void*)NULL, 0 to (HWND)0, etc. This is annoying when using functions with a lot of parameters.
Maybe there are some mistakes in the implementation but I'm not a template expert. Also, I don't know if the title of the question fits properly.
I appreciate any help.
EDIT:
What I've tried so far (#OlegBogdanov's suggestion):
template<class T, class... Args>
class encoded_ptr;
template<class T, class... Args>
class encoded_ptr<T(Args...)> {
public:
typedef encoded_ptr<T> _Myt;
using Fptr = T(*)(Args...);
encoded_ptr(Fptr ptr) {
ptr_ = (Fptr)EncodePtr((LPVOID)ptr);
}
// Makes it possible to call the function directly
typename T operator()(Args... _Ax) {
Fptr fn = get();
return fn(std::forward<Args>(_Ax)...);
}
Fptr get() const {
return (T*)DecodePtr((LPVOID)ptr_);
}
bool is_set() {
return (get() != nullptr);
}
private:
Fptr ptr_;
};
Result: Cannot instantiate / use the constructor: Incomplete type is not allowed.
EDIT:
That was the right direction, the problem was the calling convention.
Changed:
class encoded_ptr<T(Args...)> to class encoded_ptr<T(__stdcall)(Args...)>, and
using Fptr = T(*)(Args...) to using Fptr = T(__stdcall*)(Args...)
I'm trying to detect the calling convention instead of having it hardcoded.
I think your expectations of
template<class... _Args>
typename std::result_of<T*(_Args...)>::type operator()(_Args... _Ax) {
T* fn = get();
return fn(_Ax...);
}
are wrong. It completely ignore's your target functions argument list (you have used poor mans type erasure) and passes (I wanted to use word 'forwards' but that would be inaccurate) whatever caller gives in. Thus 0 in
MsgBox(0, "Test message!", "Test", 0);
is deduced as int and you have to cast it to HWND, there's no way compiler would guess it otherwise.
What you are really doing is re-inventing the std::function or sort of wrapper above it.
If you really think that std::function is not enough for your needs you will have to copy parts of its implementation, namely you would need to have at least
template<class R, class... Args>
class encoded_ptr; // leaving this undefined
template<class R, class... Args>
class encoded_ptr<R(Args...)> {
using Fptr = R(*)(Args...);
encoded_ptr(Fptr ptr) {
ptr_ = (T*)DecodePtr((LPVOID)ptr);
}
...
to capture argument list in your type
and call operator would re-use it instead of randomly typed passed arguments:
// this must not be here -> template<class... _Args>
R operator()(Args... _Ax) {
T* fn = get()
return fn(std::forward<Args>(_Ax)...);
}
Edit:
You can't store but T* anymore, T is just a return type, store by Fptr
I am looking for a way to convert function object to function pointer.
Captureless lambda has implicit conversion that allows to:
using fptr_t = int (*)(int);
fptr_t ptr = nullptr;
ptr = [](int) { return 2; };
ptr = [](auto) { return 3; };
(*ptr)(42);
I try to do the same with old-fashioned, empty class function objects like:
struct Foo {
int operator()(int) const { return 5; }
} foo;
Or std predicates like std::less<int>.
One way I found is to wrap call of foo with lambda.
If I can assure that foo is stateless and const
I dont really need this ptr and lambda-capture:
template <typename R, typename... Args>
struct to_function_pointer<R(Args...)> {
private:
template <typename T, REQUIRES(std::is_empty<T>::value)>
static T const& stateless_const() {
return (*static_cast<T const*>(nullptr));
}
public:
using pointer = R (*)(Args...);
template <typename U>
pointer operator()(U) const {
return [](Args... args) {
return stateless_const<std::decay_t<U>>()(args...);
};
}
};
But here I do not know how to provide perfect forwarding,
cause [](Args&&...) or [](auto&&...) cannot convert to R(*)(Args...).
Such trick fails when args is noncopyable like std::unique_ptr<int>.
I know that I could use std::function, but it's kind of heavy-weight, while I am trying to get a light-weight solution.
Live example.
Any advice appreciated.
I believe you can simplify your to_function_pointer with just:
template <typename R, typename... Args>
struct to_function_pointer<R(Args...)> {
using pointer = R(*)(Args...);
template <typename U, REQUIRES(std::is_empty<U>::value && std::is_trivially_constructible<U>::value)>
pointer operator()(U ) const
{
return [](Args... args) {
return U{}(std::forward<Args>(args)...);
}
}
};
Few things to note. Args... will already be references or not, you're providing that signature. So forward<> will still do the same thing - the function just happens to not be a template here. Also, scrap the weird nullptr cast. That just looks bad - if we just require trivial constructibility we can just write U{} which seems way cleaner to me.