Expressão SFINAE para sobrecarregar no tipo de ponteiro de função passado

Neste exemplo, uma função é passada para um modelo de função implicitamente instanciado.

// Function that will be passed as argument
int foo() { return 0; }

// Function template to call passed function
template<typename F>
int call(F f) {
    return f();
}

template<typename F, typename A>
int call(F f, A a) {
    return f(a);
}

int a = call(foo);

Podemos quebrar esse código adicionando uma sobrecarga parafoo().

int foo(int i) { return 0; }

O nome "foo"agora é ambíguo e o exemplo não será mais compilado. Isso pode ser feito para compilar fornecendo explicitamente informações sobre o tipo de ponteiro de função.

int (*func_takes_void)() = foo;
int a = call(func_takes_void);

int (*func_takes_int)(int) = foo;
int b = call(func_takes_int, 0);

http://coliru.stacked-crooked.com/a/e08caf6a0ac1e6b9

É possível deduzir os tipos de ponteiros de função? Se sim, por que minha tentativa abaixo não funciona e qual é a maneira correta de fazer isso?

Se isso não for possível, uma boa resposta explicaria o porquê.

Tentativa até agora

Um humano pode ver qualfoo() é planejado nas duas chamadas, inspecionando as definições decall<>() mas essas informações não estão disponíveis para o compilador para resolução de sobrecarga. Ainda assim, as informações estão todas lá, elas só precisam ser inseridas na assinatura do modelo de função. Isso pode ser possível com a expressão SFINAE.

No pseudo-código, queremos o seguinte:

template<IgnoreThis, typename ReturnType>
struct expr_check
{
    typedef ReturnType type;
}

template<typename F>
expr_check<expression requiring F have correct signature, result_of<F>::type>::type
call(F f);

Aqui está essa ideia elaborada em código real.

http://coliru.stacked-crooked.com/a/a3ce828d6cb16c2d

As assinaturas do modelo de função são:

template<typename F>
typename expr_check<sizeof(declval<F>()()), typename func_ptr_result<F>::type>::type
call(F f);

template<typename F, typename A>
typename expr_check<sizeof(declval<F>()(declval<A>())), typename func_ptr_result<F>::type>::type
call(F f, A a);

O que eu tenho atualmente não é compilado. Na saída do compilador, você pode ver que nas duas tentativas de instanciar o modelo de função, há uma falha de substituição em umcall<>() sobrecarga e o outro simplesmente fornece um opaco "não foi possível deduzir o parâmetro do modelo".

(O colirus foi compilado como C ++ 03, mas as respostas C ++ 11 estão boas.)

Minha suspeita é que, ao instanciarcall<>(), foo() não está sendo chamado e o C ++ simplesmente não fornece resolução de sobrecarga defoo() neste contexto. Não importa que se possa provar que umfoo() sobrecarga é a correta, C ++ simplesmente não exige resolução de sobrecarga aqui. Por outro lado, a resolução de sobrecarga não se limita a uma função que está sendo chamada. Um ponteiro de função do tipo apropriado pode selecionar sobrecargas defoo().

Perguntas relacionadas

Existem algumas perguntas sobre sobrecarga no tipo de ponteiro de função. Parece que isso não pode ser feito. Não encontrei nenhuma dúvida tentando fazer isso através da expressão SFINAE.

Esta parece ser a questão mais próxima.

Existe uma maneira de deduzir o valor de um parâmetro de modelo de ponteiro de função?

Pedantaria bônus

"Ponteiro de função" é a frase correta a ser usada no título? A "referência de função" teria sido mais precisa?

questionAnswers(2)

yourAnswerToTheQuestion