How does NSData(bytes:length:) convert [Byte] to UnsafePointer<Void> in Swift? - casting

Playing with raw data in Swift I came across something I don't understand.
NSData has a constructor:
init(bytes: UnsafePointer<Void>, length: Int)
where the first bytes parameter is clearly of UnsafePointer type.
However, if I pass [Byte] object to this constructor, not only does the compiler not complain, but it works ok.
But if I try to cast [Byte] to UnsafePointer, I fail.
How does this work?
For example (you can try it in Playgrounds):
let buffer: [Byte] = [0x00, 0xff]
let data = NSData(bytes: buffer, length: buffer.count) // no error
data.description
var pointer: UnsafePointer<Void>
// comment this line to avoid compiler error
pointer = buffer // error
I know I can do
UnsafePointer<Void>(buffer)
but my question is, what does NSData constructor do implicitly, that I don't have to do that.

Swift maps its own types to C pointers when you're calling a C function that requires them. Apple has a bit of documentation on this interaction: Interacting with C APIs.
In short, when you're calling a function that takes an UnsafePointer<Type>, it can accept nil, an inout variable of that type, an array of that type (i.e., [Type], what you're using), or one of the generic Swift pointer types. A function taking UnsafePointer<Void> can take any of those, with no constraint on the type at all, so you need to read the function's documentation to see what it expects/will return.

Related

QVariant wrapped pointers turn to null in QML

It seems like something is going wrong when pointer values transcend between C++ and QML world. I am using the plain old fromValue() and value() to convert to and from void *, and it does work as expected as long as the variant stays on the C++ side.
The moment it is returned to QML, it now resolves to null, and when passed back to C++, the variant type is changed from void * to std::nullptr_t and the value is null.
returning 0x3ba5b10 // created
converting to qvariant 0x3ba5b10 // converting
converted QVariant(void*, 0x3ba5b10) 0x3ba5b10 // now variant, testing value() - all good
qml: null // in qml
received QVariant(std::nullptr_t, (nullptr)) 0x0 // back in c++
I am using:
Q_DECLARE_METATYPE(void*)
qRegisterMetaType<void*>();
Any clue as to what is going on here?
Edit: it keeps even more strange, I get it to work by casting the pointer values to 64 bit uint and back, but upon the transition to QML, the type info gets messed up, in C++ the variant is of type qulonglong, arriving back from QML it is now a double, hence the suspicion it might round something and mess up the pointer value.
Edit 2: note that the question is not about recommending practices but about why this doesn't work as expected and observed prior to reaching QML.
You don't need to register void*, rather use the metatype QMetaType::VoidStar.
Note that to register the metatype SomeCustomType*, you need to use an alias.
using SomeCustomTypePtr = SomeCustomType*;
Q_DECLARE_METATYPE(SomeCustomTypePtr)
qRegisterMetaType<SomeCustomTypePtr>();
Isn't even possible to do such declarations?
According to official documentation on Q_DECLARE_METATYPE(Type):
This macro makes the type Type known to QMetaType as long as it provides a public default constructor, a public copy constructor and a public destructor. It is needed to use the type Type as a custom type in QVariant.
This macro requires that Type is a fully defined type at the point where it is used.
Sounds strange that this works at least in C++ part.
Don't you think that it will be better and straight-forward solution to declare your type pointer instead of void*?

'&' : illegal operation on bound member function expression [duplicate]

This question already has answers here:
Print address of virtual member function
(5 answers)
Closed 8 years ago.
This works when I try from a single cpp file with a main function,
sprintf(smem_options ,
"#transcode{vcodec=RV24}:smem{"
"video-prerender-callback=%lld,"
"no-time-sync},"
, (long long int)(intptr_t)(void*)&cbVideoPrerender
);
How do I pass function arguments to sprintf within a class?
sprintf(smem_options ,
"#transcode{vcodec=RV24}:smem{"
"video-prerender-callback=%lld,"
"no-time-sync},"
, (long long int)(intptr_t)(void*)&cbVideoPrerender
);
The error message I get is: error C2276: '&' : illegal operation on bound member function expression
Assuming cbVideoPrerenderer is a member function in the second example, you need to say &Foo::cbVideoPrerenderer where Foo is the class it is a member of.
But that will only be valid if it is a static member function. Non-static member functions are not like normal functions, and when you form a pointer-to-member-function with the &Foo::bar syntax the thing you get back cannot be converted to a void* (it is typically something twice as large as a pointer, as it contains information about the object type).
What you're trying to do is conditionally supported behavior in C++11,
and illegal in earlier versions, in both cases. You can't reliably
convert a pointer to a function (member or otherwise) to a void*.
(I've worked on systems where a pointer to a function was 32 bits, but a
void* only 16.)
In practice, most compilers will (illegally, in pre-C++11) ignore the
error for non-member functions. Posix requires that function
pointers and data pointers be compatible, and they are under Windows as
well. (Today: only of the systems where they weren't for me was an
early Unix.) As for pointers to members: a pointer to a static member
has a type compatible to a pointer to a function (and so will work in
practice, if the compiler allows it), but a pointer to a non-static
member has a completely different type, usually with a different size,
and a different representation. About the only way you can reliably
output one is as a series of byte values: put the address in a properly
typed variable, take the address of that variable, convert it to
unsigned char const*, then use "%02x" to output each byte.
But the real question is why you want to do this. There is nothing that
you can reliably do with the value you output, regardlessly of how you
output it.

Why can't I use type []chan *Message as type []chan interface{} in a function argument?

This is the error message I am getting:
cannot use c.ReceiverChans (type []chan *Message) as type []chan interface {} in function argument
The types are different. A *Message implements the empty interface, but that doesn't mean you can take a slice or chan of *Message and pass it to something that expects a slice or chan of interfaces.
The way I think of interfaces as a particular data structure; a pair of a pointer to a value and a pointer to the underlying type. It's not exactly how interfaces work, but it helps my intuition. Using this intuition, if I pass an int, say, to a function that wants an interface{}, I imagine my value getting wrapped inside this interface pair implicitly by the compiler before the function's called. If instead, the function expects a []interface{}, and I want to pass a []int, what can the compiler do? It would have to construct a new array of the interface pairs, but then (a) that'd be expensive, and (b) it wouldn't really work, since if for example the slice got sorted, the original slice would be left alone.
Here's the question in the golang FAQ: http://golang.org/doc/faq#convert_slice_of_interface
Here's a more detailed explanation about slices of interfaces from the go wiki which explains better than I just did.
https://code.google.com/p/go-wiki/wiki/InterfaceSlice

C++ Extract std::string from a variable-length argument list

Hey everyone! I'm trying to make a simple copy of sprintf that returns the formatted string, but I am coming into a small snag...
Apparently, using a variable-length argument list you cannot pass a std::string instance.
I already have the parser working properly with int, double, float, char, const char*, char*... I have yet to get strings to work. :\
In case you're wondering, this is the compile error I get: /root/learncpp/StringFormat/main.cpp:8: warning: cannot pass objects of non-POD type 'struct std::string' through '...'; call will abort at runtime
The main reason I'm doing this is so that I can have convenient formatting without having to rely on 3rd party libraries, yet still not have to append ".c_str()" to every string instance I use.
Help with this would be appreciated. Perhaps there's a different version of variable-length argument lists made specifically for C++?
EDIT: I have just realized, if you pass a pointer to a string (i.e. using the & prefix) it works well. All you have to do is dereference a string pointer in the custom sprintf, while passing the address of the std::string!
Still, it would be nice to see if there's any way to support string directly through variable-length argument lists. Thanks!
No -- as the compiler said, you're only allowed to pass objects of POD type to a variadic function.
What you normally want to do is eliminate using a variadic function in the first place, such as by using an iostream instead of something like printf (or a stringstream instead of sprintf).

(Obj) C++: Instantiate (reference to) class from template, access its members?

I'm trying to fix something in some Objective C++ (?!) code. I don't know either of those languages, or any of the relevant APIs or the codebase, so I'm getting stymied left and right.
Say I have:
Vector<char, sizeof 'a'>& sourceData();
sourceData->append('f');
When i try to compile that, I get:
error: request for member 'append' in 'WebCore::sourceData', which is of non-class type 'WTF::Vector<char, 1ul >& ()();
In this case, Vector is WTF::Vector (from WebKit or KDE or something), not STD::Vector. append() very much is supposed to be a member of class generated from this template, as seen in this documentation. It's a Vector. It takes the type the template is templated on.
Now, because I never write programs in Real Man's programming languages, I'm hella confused about the notations for references and pointers and dereferences and where we need them.
I ultimately want a Vector reference, because I want to pass it to another function with the signature:
void foobar(const Vector<char>& in, Vector<char>& out)
I'm guessing the const in the foobar() sig is something I can ignore, meaning 'dont worry, this won't be mangled if you pass it in here'.
I've also tried using .append rather than -> because isn't one of the things of C++ references that you can treat them more like they aren't pointers? Either way, its the same error.
I can't quite follow the error message: it makes it sound like sourceData is of type WTF:Vector<char, 1ul>&, which is what I want. It also looks from the those docs of WTF::Vector that when you make a Vector of something, you get an .append(). But I'm not familiar with templates, either, so I can't really tell i I'm reading that right.
EDIT:
(This is a long followup to Pavel Minaev)
WOW THANKS PROBLEM SOLVED!
I was actually just writing an edit to this post that I semi-figured out your first point after coming across a reference on the web that that line tells the compiler your forward declaring a func called sourceData() that takes no params and returns a Vector of chars. so a "non-class type" in this case means a type that is not an instance of a class. I interpreted that as meaning that the type was not a 'klass', i.e. the type of thing you would expect you could call like .addMethod(functionPointer).
Thanks though! Doing what you suggest makes this work I think. Somehow, I'd gotten it into my head (idk from where) that because the func sig was vector&, I needed to declare those as &'s. Like a stack vs. heap pass issue.
Anyway, that was my REAL problem, because I tried what you'd suggested about but that doesn't initialize the reference. You need to explicitly call the constructor, but then when I put anything in the constructor's args to disambiguate from being a forward decl, it failed with some other error about 'temporary's.
So in a sense, I still don't understand what is going on here fully, but I thank you heartily for fixing my problem. if anyone wants to supply some additional elucidation for the benefit of me and future google people, that would be great.
This:
Vector<char, sizeof 'a'>& sourceData();
has declared a global function which takes no arguments and returns a reference to Vector. The name sourceData is therefore of function type. When you try to access a member of that, it rightfully complains that it's not a class/struct/union, and operator-> is simply inapplicable.
To create an object instead, you should omit the parentheses (they are only required when you have any arguments to pass to the constructor, and must be omitted if there are none):
Vector<char, sizeof 'a'> sourceData;
Then you can call append:
sourceData.append('f');
Note that dot is used rather than -> because you have an object, not a pointer to object.
You do not need to do anything special to pass sourceData to a function that wants a Vector&. Just pass the variable - it will be passed by reference automatically:
foobar(sourceData, targetData);
Dipping your toes in C++ is never much fun. In this case, you've run into a couple of classic mistakes. First, you want to create an instance of Vector on the stack. In this case the empty () is interpreted instead as a declaratiton of a function called sourceData that takes no agruments and returns a reference to a Vector. The compiler is complaining that the resulting function is not a class (it's not). To create an instance of Vector instead, declare the instance without the () and remove the &. The parentheses are only required if you are passing arguments to the instance constructor and must be omitted if there are no arguments.
You want
Vector<char, sizeof 'a'> sourceData;
sourceData.append('f');
Vector<char, sizeof 'a'> outData; //if outData is not instantiated already
foobar(sourceData, outData);
This Wikipedia article gives a decent introduction to C++ references.