Tenho um problema que se resume a um exemplo como este:
#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);
}
Ou seja, eu tenho uma função direct()
que recebe um argumento do tipo data
. data
é construtível a partir de um array de estilo C de comprimento fixo. Eu tenho outro par de funções, call_direct()
e call_via_ptr()
, que encaminham seu único argumento de modelo para a função, seja invocando-a diretamente ou por meio de um ponteiro de função.
A call_direct()
abordagem funciona bem. No entanto, ele call_via_ptr()
falha ao compilar em versões do gcc até 14.2 , gerando um erro como:
<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*
No entanto, ele compila bem em todas as versões do clang que testei.
Parece que ao chamar a função por meio de um ponteiro de função, o argumento array está decaindo para um float *
, que não é conversível para data
, daí o erro. No entanto, não está claro para mim por que o decaimento do ponteiro funcionaria de forma diferente entre os dois casos.
Existe algum ajuste que eu possa fazer aqui para permitir que isso seja construído no gcc? Qual compilador está correto aqui?