4

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?

4
  • 2
    Out of curiosity, what happens if you use a C++ array (std::array) instead of a C-style array? Commented Mar 3 at 15:06
  • std::array (or any other C++ object type) works fine, which makes sense as the issue seems to be array-to-pointer decay. Commented Mar 3 at 15:09
  • Another data point: (*func_ptr)(data{std::forward<T>(t)}); works for g++-14 -std=c++17. Commented Mar 3 at 15:15
  • Even removing template part, and just call func_ptr(arr) fails :-/ Demo Commented Mar 3 at 15:39

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.