问题描述:

So I was writing a function which shall act like one, returning an array (as you know arrays are not allowed to be returned in C++) and for that I need one temporary unnamed which shall be used as default parameter value assigned to the last argument implicitly, like this:

template<size_t szArr, typename typeArrs>

auto fnAdd2ArrayElements(const typeArrs (&arr_0)[szArr], const typeArrs (&arr_1)[szArr], typeArrs (&&result)[szArr] = {}) -> typeArrs (&&)[szArr]

{

for(size_t i(0); i < szArr; ++i)

result[i] = arr_0[i] + arr_1[i];

return move(result);

}

As you can see the 'result' parameter have a default parameter value an unnamed array which however will be always 'zero-filled', because of the empty brackets. This will decrease performance because as you can see my function doesn't cares of it's contents and will fill it all. Is there anyway I can declare it uninitialized. Something like this:

template<typename T, size_t sz> using identity = T [sz];

template<size_t szArr, typename typeArrs>

auto fnAdd2ArrayElements(const typeArrs (&arr_0)[szArr], const typeArrs (&arr_1)[szArr], typeArrs (&&result)[szArr] = identity<typeArrs, szArr> ()) -> typeArrs (&&)[szArr]

{

for(size_t i(0); i < szArr; ++i)

result[i] = arr_0[i] + arr_1[i];

return move(result);

}

But the above code won't compile. So any ideas how this can be done?

EDIT: It seems another problems appear. Since we are returning an 'xvalue' (and not an 'prvalue'), if we store the result in an 'rvalue' reference, the life-time of the unnamed temporary wouldn't extends as if we have returned an array by value. Here is an example:

const int iArr[] = {0, 1, 2, 3, 4};

const int iArr1[] = {0, 1, 2, 3, 4};

int (&&added)[5] = fnAdd2ArrayElements(iArr, iArr1); //this will create an dangling reference

added[0]; //illegal - accessing dangling reference

网友答案:

It would be risky since the lifetime of this temporary is short:

template <typename T, size_t N>
struct UninitializedArray
{
    UninitializedArray() {}
    T arr[N];
};

template <size_t szArr, typename typeArrs>
typeArrs (&&)[szArr]
fnAdd2ArrayElements(
    const typeArrs (&arr_0)[szArr],
    const typeArrs (&arr_1)[szArr],
    typeArrs (&&result)[szArr] = UninitializedArray<typeArrs, szArr>{}.arr)
{
    std::cout << result[0] << std::endl; // To check that value is not initialized.

    for (size_t i(0); i < szArr; ++i) {
        result[i] = arr_0[i] + arr_1[i];
    }
    return std::move(result);
}

Live example

网友答案:

I don't think there's a good way to do this as you can't return an array as you correctly indicate.

An alternative approach would be to overload the function and within that overload, call the other function with the array parameter appropriately defined. (That's the only approach available to Java by the way).

网友答案:

The problem here is that passing pointers to a function makes the function arguments decay to pointers (even if your code call them references, they are pointers). You can't return a pointer "into an array" - that would essentially mean that the compiler would have to do memcpy(dest, fnAdd2ArrayElements(...), number_of_bytes);, but it doesn't know the actual length of the number_of_bytes from the code.

Your code that you have already use three array arguments, so you could simply make the function into

void fnAdd2ArrayElements(const typeArrs (&arr_0)[szArr], 
                         const typeArrs (&arr_1)[szArr], 
                         typeArrs (&result)[szArr]);

You will, however, have to initialize the original result.

Alternatively, and this is my preferred solution: use std::vector [or similar].

相关阅读:
Top