C++: What is semantics of std::function constness? - c++11

Reference says that std::function::operator() is const. What this constness applies to? If std::function is a wrapper around callable object, does constness applies to this object (meaning its operator() should be const too?).
Overall, what does it mean for std::function to be const for different kinds of targets (lambda, function pointer, object, member function, etc)?

It is a bug. Nothing is actually const as the target object is called from a non-const reference, per the specification.
A future revision of the standard library will remove const from the call operator. Users will be able to specifically request a properly const call using specializations such as std::function<return_type(arg_type) const>.
See standard proposal P0045. (Disclosure: I'm the author.)

Related

What is the best type for a callable object in a template method?

Every time I write a signature that accepts a templated callable, I always wonder what the best type for the parameter is. Should it be a value type or a const reference type?
For example,
template <class Func>
void execute_func(Func func) {
/* ... */
}
// vs.
template <class Func>
void execute_func(const Func& func) {
/* ... */
}
Is there any situation where the callable is greater than 64bits (aka a pointer to func)? Maybe std::function behaves differently?
In general, I do not like passing callable objects by const reference, because it is not that flexible (e.g. it cannot be used on mutable lambdas). I suggest to pass them by value. If you check the stl algorithms implementation, (e.g. for std::for_each), all of the callable objects are passed by value as well.
Doing this, the users are still able to use std::ref(func) or std::cref(func) to avoid unnecessary copying of the callable object (using reference_wrapper), if desired.
Is there any situation where the callable is greater than 64bits
From my experience in working in CAD/CAE applications, a lot. Functors can easily hold data that is bigger than 64 bits. More than two ints, more than one double, more than one pointer, is all you need to exceed that limit in Visual Studio.
There is no best type. What if you have noncopyable functor? First template will not work as it will try to use deleted copy constructor. You have to move it but then you will loose (probably) ownership of the object. It all depends on intended use. And yes, std::function can be much bigger than size_t. If you bind member function, it already is 2 words (object pointer and function pointer). If you bind some arguments it may grow further. The same goes with lambda, every captured value is stored in lambda which is basically a functor in this case. Const reference will not work if your callable has non const operator. Neither of them will be perfect for all uses. Sometimes the best option is to provide a few different versions so you can handle all cases, SFINAE is your friend here.

What does all capitalized Function name means in WinAPI?

Informs the provider that a directory enumeration is starting
`
PRJ_START_DIRECTORY_ENUMERATION_CB PrjStartDirectoryEnumerationCb;
HRESULT PrjStartDirectoryEnumerationCb(
const PRJ_CALLBACK_DATA *callbackData,
const GUID *enumerationId
)
{...}
`
I am confused how to use this function.
You're looking at a callback (a generic programming concept, not specific to Win32), which is usually a reference to a function that you have to write yourself. In order to have the C/C++ compiler check that you've defined your callback function correctly, and to simplify usage of such callbacks, a typedef is often used. The Win32 API often uses all caps to define types of callbacks. In this case, PRJ_START_DIRECTORY_ENUMERATION_CB is the type of the function pointer (a pointer to the callback function that you have to write), and it is defined in projectedfslib.h as:
typedef
_Function_class_(PRJ_START_DIRECTORY_ENUMERATION_CB)
HRESULT
(CALLBACK PRJ_START_DIRECTORY_ENUMERATION_CB)(
_In_ const PRJ_CALLBACK_DATA* callbackData,
_In_ const GUID* enumerationId
);
This definition has a lot of excess stuff in it that helps the Microsoft toolset validate various things related to the usage of this type of function pointer. When writing your own function that works for this type of callback, you don't necessarily have to repeat a lot of the things that are used in the typedef. The MSDN documentation for callbacks often shows an example of how you would write the method signature for your callback, and that example is usually simplified to strip off the excess stuff that the toolset needs, leaving the stuff the developer needs to define when writing their callback.
In this case, the example function is called PrjStartDirectoryEnumerationCb, but there is no function defined with that name. It's up to you to define a function that looks like what you see on MSDN. It doesn't have to have the same name -- you can name it whatever you like, and then you use your function's name anywhere the callback is needed.
HRESULT MyCallback(const PRJ_CALLBACK_DATA *callbackData, const GUID* enumerationId)
{
// implement your callback here
}

Making a template function work with both lvalue and rvalues pointer arguments

I currently have a memory leak in my project. To resolve the memory leak, I am trying to replace the pointers into std:: unique_ptr. The pointer to the heap is not from my project, but rather from a library called Xerces(an XML parsing library).
In this library, it can transcodes char * to XMLCh * in both ways.
So in real code, it comes like ..
XMLCh * xmlstr = XMLString::transcode("abc",...);
char * charstr = XMLString::transcode(xmlstr,...);
since both methods allocates heap area and returns the pointer for it, I should explicitly call
XMLString::release(xmlstr);
XMLString::release(charstr);
after using it to clean up. I want to write a custom deleter for two types (char * and XMLCh *) using std::unique_ptr.
The release method has a type of
XMLString::release(char **str);
XMLString::release(XMLCh **str);
It is using double pointer because it sets the pointer to null after release.
I thought to make the template accept reference pointers like this,
template<typename T>
void release(T *& ptr){
XMLString::release(ptr);
}
but just realized that it will be possible to
XMLCh * xmlstr = XMLString::transcode("abc",...);
auto uptr = unique_ptr<XMLCH, decltype(&release<T>)>(xmlstr)
do this, but not possible to
auto xmluptr = unique_ptr<XMLCH, decltype(&release<T>)>(XMLString::transcode("abc",...));
do something like this, because it is accepting a rvalue in the parameter but the argument is a reference pointer. Is it possible to instantiate both cases writing only one template function?
By the way, I am using c++11.
So if I understand correctly, your problem is that XMLString::release takes a pointer-to-point and it does not fit into the unique_ptr release function. Well, the correct solution is to wrap it like
template<typename T>
void release(T *ptr){
XMLString::release(&ptr);
}
The XMLString::release will only null-out the copy of the pointer inside the wrapper, but since the unique_ptr takes care of rendering itself unusable itself, you don't need that functionality of XMLString::release.
In either case, the type of the release wrapper does not affect how the unique_ptr is constructed, because the release wrapper will be called with the internal member of the unique_ptr as argument. So either unique_ptr accepts that argument, and both assignments will work, or unique_ptr won't accept it and neither will.
That said, the point of unique_ptr is that you wrap the pointer in it immediately when you get it. So don't store it in variable before.

ABI in pimpl idiom with unique_ptr

My goal is to provide abi compatibility for my new library.
I look toward the using of unique_ptr instead of raw pointers. But I'm afraid that if I update standard library, I may break abi. Is it true? Is there any guaranty of abi-stability for unique_ptrs in future stdlib releases?
As you can see from this blog post the problem is known and it is being addressed. As things stand now I'm afraid the best you can do is check with your compiler supplier whether they provide any guarantee (e.g. not to break ABI in minor releases).
The problem rise when you use a custom deleter. unique_ptr (unlike shared_ptr) destructor requires knowing a complete type of the object. So you need to specify the deleter in the data member declaration:
class Foo {
private:
std::unique_ptr <FooImpl> _pimpl;
};
When instantiating the pimpl you are constrained to using the default deleter.
If you want a custom deleter, you need to specify it in the declaration
class Foo {
private:
std::unique_ptr <FooImpl, std::function <void (FooImpl*&)> > _pimpl;
};
However, you can't have the option to be flexible whether you want the unique_ptr d'tor to call the default delete or a custom deleter.
The more flexible option is the second version, but if you choose to keep with the default behavior, then you must instantiate the unique_ptr with a specific deleter that is equivalent to the default delete.
IMO, this is a significant drawback for unique_ptr to be used for pimpl idiom.

Calling a property on the const reference

I have C++/CLI class that defines a property:
public ref class AbstractOffer
{
public:
AbstractOffer();
property String^ Body;
};
In some function the AbstractOffer class is passed by const ref
foo(const AbstractOffer^ ao)
{
ao->Body;
}
When I call the property the method compiler gives the following error :-
error C2662: 'ivrworx::interop::AbstractOffer::Body::get' : cannot
convert 'this' pointer from 'const ivrworx::interop::AbstractOffer'
to 'ivrworx::interop::AbstractOffer %' 1> Conversion loses
qualifiers
It seems somehow connected to const. How can I call the Body property of the object if the object reference is passed by const?
The const qualifier is a problem in C++/CLI. It is only meaningful when it can be checked and that's not in general possible in .NET. It is of course not a problem when you only have one kind of compiler and that compiler follows strict language rules. Like C++. But .NET supports many languages, your method could be easily called from a Cobol.NET program for example. The odds of ever getting const-correctness added to the Cobol language are zero.
The compiler does compile code with const qualifiers and does make an effort to check when it can. Which is why you got the diagnostic. That can even work when the declaration exists in another assembly, as long as it was compiled with C++/CLI, the compiler emits modopt annotations in the metadata.
But there are limitations with that. Properties are one of them, you can't add the const qualifier to the getter, or a member function in general, you'll get slapped with C3842.
Best thing to do is to use C++/CLI for what it is good at, it is an interop language. And const qualifiers just don't work well in an interop scenario.
The only way I know to get round this is the cast away the const-ness. As long as you don't modify the object, it should be fine. (If you do modify it, I've no idea what the outcome will be).
i.e. change your function to be
void foo(const AbstractOffer^ ao)
{
const_cast<AbstractOffer^>(ao)->Body;
}

Resources