2015-06-03 2 views
6

Почему не может быть выведено F для proxy()?Не удается вывести аргумент шаблона, который является функцией

Это должно быть возможно, потому что я ограничиваю его - только для функций, возвращающих int.

#include <utility> 
#include <iostream> 
#include <type_traits> 
using namespace std; 

int foo(int bar) { 
    cout << "int" << endl; 
    return 2; 
} 

float foo(float bar) { 
    cout << "float" << endl; 
    return 1; 
} 

template <typename F, typename... Args> 
typename enable_if< 
    is_same< 
     typename result_of<F(Args...)>::type, 
     int 
     >::value, 
    typename result_of<F(Args...)>::type 
    >::type 
proxy(F func, Args&&... args) { 
    return func(forward<Args>(args)...); 
} 

int main() { 
    proxy(foo, 5); 
} 

Здесь ошибка:

b.cpp:29:17: error: no matching function for call to 'proxy(<unresolved overloaded function type>, int)' 
b.cpp:24:1: note: template argument deduction/substitution failed: 
b.cpp:29:17: note: couldn't deduce template parameter 'F' 
+0

Поскольку две перегруженные функции ... Компилятор не может вывести значение посредствои будущий (следующий) параметр функции ...'proxy (static_cast (foo), 5);' будет делать трюк здесь –

ответ

4

Проблема заключается в следующем:

proxy(foo, 5); 

компилятор пытается вывести тип foo, но есть 2 перегрузках. Конечно, он может выводить Args... от 5, но тип foo по-прежнему не выводим, так как компилятор не знает, какую перегрузку выбрать при выполнении вывода типа.

Обратите внимание, что компилятор должен знать тип F в подписи функции, то есть здесь, так SFINAE делать свою магию:

is_same< 
    typename result_of<F(Args...)>::type, 
    int 
>::value, 

Там нет абсолютно никакого способа для того, чтобы правильно вывести тип от F от вызова proxy(foo, 5), поэтому SFINAE не может вбить. В качестве примечания обратите внимание, что C++ не может перегружать только на основе типа возврата. Таким образом, вы не сможете дифференцировать две функции с тем же именем, основанные только на обратном типе. Вам нужно каким-то образом принудительно выполнить сопоставление параметров, которое будет вызывать SFINAE из перегрузок, не являющихся кандидатами.

как-то связаны: Deducing the return type of a standalone function

И соответствующую цитату из стандарта, подчеркнуть мое (благодаря @TC для указания его):

14.8.2.1 Выведение аргументы шаблона из вызова функции [темп .deduct.call]/(6,2)

(6) When P is a function type, pointer to function type, or pointer to member function type:

  • (6.1) If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.

  • (6.2) If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.

+0

, но почему он не пытается с каждым из них и не видит, как далеко он попадет в экземпляр/подстановку шаблона ? Есть ли способ обойти это без явного приведения? – onqtam

+0

@onqtam Я думаю, это слишком сложно, поскольку для компилятора первый параметр 'F' не имеет ничего общего со вторым« Args ... ». Я попытаюсь придумать обходное решение. – vsoftco

+0

Эта проблема воспроизводима без аргументов - только при использовании возвращаемого типа ... Думаю, я должен был бы привести более простой пример – onqtam

2

в вашем примере foo имена набор перегруженных функций, и аргумент шаблона вычет не может выбрать о ne перегружают друг друга, потому что они оба соответствуют равному рангам.

Ваша проверка ограничений SFINAE не срабатывает до тех пор, пока не будет выведено значение F, так что это не поможет в сбросе float foo(float) из набора разрешений перегрузки.

Скажите, что вы переименовали функцию, возвращающую float в foof, тогда ваш пример будет скомпилирован. Но если вы попытались позвонить proxy с foof в качестве аргумента функции, код снова не сможет скомпилироваться, на этот раз из-за ограничения enable_if.

Чтобы получить пример компиляции в его текущем состоянии вы должны неоднозначности, которые foo вы передаете в proxy

proxy(static_cast<int(*)(int)>(foo), 5); 
+0

Я догадываюсь, что я еще не совсем понял SFINAE, потому что думал, что это поможет мне здесь ... – onqtam

Смежные вопросы