if I try retuning nullptr, it won’t work if I use that function for literals. Is there any way to get the default value for a template?
(ex: if it’s a string it be “”, 0 for int, nullptr for object, etc)
Edit: Don’t know why the codebox is so big, it’s normal in the edit-post.
You would have to return something, so possibly a new default-constructed element. Alternatively (and preferably) though, you can pass in a default element to return if nothing is found (similar to how TMap::FindRef works).
As another approach, you could return a pointer to an element, and check if it’s valid when returning:
This is a pre-condition of your function. You have two choices:
a.) Ignore it, dump responsibility to caller
b.) Express it clearly that function may fail, explicitly in function signature, for example by
I wouldn’t recommend returning a pointer. This is a template, so you don’t know what T is. If your array is TArray <SomeClass *> then nullptr may be the correct result and then you won’t be able to recognize it is a fail or not.
The problem is that I wouldn’t be able to use that with literals: GetRandElem<FName>(ar);
The compiler sees it’s nullptr return type and errors on using FName, int, etc.
Thanks, but I can’t seem to understand what TOptional does.
What how would I return if the array was empty? What would the type be for FName, uint8, etc?
It would return a double pointer, the first pointer would be the indication of whether it failed or not, the second would be the actual value. This is the same way TArray::Find() works when you have pointer elements:
The trouble with TOptional is that it holds a copy, so when you have a TArray that potentially contains another TArray, or a struct, you could be copying large amounts of data around - in which case I’d say you’re better off ignoring the template entirely and just doing it in-place where you need to.
It returns a pointer to a literal, which you can then dereference if it’s not null. You can’t return a literal from this template anyway, precisely because you don’t know if it will return a value or not. The alternative is to pass in a default value to return if it doesn’t find anything.
Yep, that’s also a valid point. If you want to return a reference, then whoever is using the type should already be able to garauntee something will be returned. Again you can look at the engine containers for an example of this, with TMap’s FindChecked().
If will return a reference, but if it can’t, you hit an assert.
Overengineering for me
You can’t return pointer to local variable, so it involves allocation. This will not be the most effective solution for cheap types.
Sure, T can by anything. No one say generic-programming is easy
It would return a pointer to the array element directly, so there’s no allocation involved. TOptional and a literal on the other hand both involve creating new data.
Returning a pointer to T instead of a literal T still seems like the best solution to me:
Handles any type (pointer to or not, including pointers to nullptr)
Handles arrays with no elements.
Return value allows you to determine a) if the function succeeded and b) what the value is.
Doesn’t require any copying or data.
Doesn’t require you having to return a default value (dangerous considering you can’t assume T() returns a value that is initialized and safe to use, and you also have no way to differentiate that from a default-constructed T within the array)
Doesn’t require you having to provide a default return value if nothing is found.
Returning a reference is also possible and would give you the “literal” in a sense, but the caller would have to garauntee that the array has at least one entry and fire an assertion if not. Doesn’t seem like a fit in this case.
I referred to the suggestion of returning a double-pointer.
Totally agree, but then function should be named GetRandomElementPtr/TryGetRandomElement.
But you have to remember that, any add/insert/etc. on that array can invalidate this pointer and this enforce strict control of scope where you use it.