Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I forward an array type to a function invoked via pointer perfectly, without the argument decaying?

I have an issue that boils down to an example like this:

#include <cstdlib>
#include <utility>

// class that is constructible from a `float` array type
struct data
{
    template <size_t N>
    data(float (&arr)[N]) { }
};

// function that takes an instance of `data`
void direct(data) { }
// pointer to the above function
void (*func_ptr)(data) = &direct;

// forward the argument to the function directly
template <typename T>
void call_direct(T && t)
{
    return direct(std::forward<T>(t));
}

// forward the argument to the function invoked via pointer
template <typename T>
void call_via_ptr(T && t)
{
    return (*func_ptr)(std::forward<T>(t));
}

int main()
{
    float arr[4];

    call_direct(arr);
    call_via_ptr(arr);
}

That is, I have a function direct() that takes an argument of type data. data is constructible from a fixed-length C style array. I have another pair of functions, call_direct() and call_via_ptr(), which forward their single template argument to the function, either invoking it directly or via a function pointer.

The call_direct() approach works fine. However, the call_via_ptr() fails to compile on gcc versions through 14.2, yielding an error like:

<source>: In instantiation of 'void call_via_ptr(T&&) [with T = float (&)[4]]':
<source>:35:17:   required from here
   35 |     call_via_ptr(arr);
      |     ~~~~~~~~~~~~^~~~~
<source>:27:39: error: could not convert '(float*)std::forward<float (&)[4]>((* & t))' from 'float*' to 'data'
   27 |     return (*func_ptr)(std::forward<T>(t));
      |                        ~~~~~~~~~~~~~~~^~~
      |                                       |
      |                                       float*

However, it does compile fine on all clang versions that I have tried.

It looks like when calling the function via a function pointer, the array argument is decaying to a float *, which is not convertible to data, hence the error. However, it isn't clear to me why the pointer decay would work differently between the two cases.

Is there a tweak I can make here to allow this to build on gcc? Which compiler is correct here?

like image 964
Jason R Avatar asked Oct 25 '25 06:10

Jason R


1 Answers

This is a documented bug in GCC. That is to say that clang (and msvc) are correct.

Here is the "meta-bug" covering a few variations on it. Like this which applies even when there is no template.

clang is correct because zero standard conversions should be required to match the target function.

like image 157
AndyG Avatar answered Oct 26 '25 20:10

AndyG