Перегрузка аргумента std:: function для соответствия lambda
Возможный дубликат:
Disambiguating вызовы функций, принимающих std:: functions
Не является ли аргумент шаблона (подпись) части std:: function его типа?
Я хочу перегрузить функцию, чтобы она могла быть вызвана с различными различными лямбдами (как правило, с более или менее аргументами). Очевидная вещь, которую я пробовал:
#include <functional>
#include <iostream>
extern void fn(std::function<void(int)>);
extern void fn(std::function<void(int, int)>);
void test()
{
fn([](int a) { std::cout << "lambda with 1 arg " << a << std::endl; });
}
Однако это не с g++ (проверено v4.6.2 и v4.7.1) с ошибкой:
test.cc: In function ‘void test()’:
test.cc:9:74: error: call of overloaded ‘fn(test()::<lambda(int)>)’ is ambiguous
test.cc:9:74: note: candidates are:
test.cc:4:13: note: void fn(std::function<void(int)>)
test.cc:5:13: note: void fn(std::function<void(int, int)>)
Теперь я нашел альтернативный (и гораздо более сложный) подход здесь и здесь, но мой вопрос является, почему приведенный выше код не работает? Есть ли что-то в стандарте, в котором говорится, что он не может работать, или это просто ошибка/ограничение g++?
Ответы
Ответ 1
Каждая Lambda [](int a) { std::cout << "lambda with 1 arg " << a << std::endl; }
имеет уникальный тип, даже другой лямбда, такой же, как указано выше, приведет к разному лямбда-типу с элементом operator()(int a)
В вашей реализации std::function
есть шаблонное преобразование, которое может использоваться как std::function<void(int)>
, так и std::function<void(int, int)>
. Хотя только один из них компилируется при создании экземпляра, они оба рассматриваются для разрешения перегрузки, и это создает неоднозначность. Чтобы получить желаемый результат, библиотеке необходимо использовать SFINAE, чтобы исключить ошибочный из набора кандидатов перегрузки (это делают последние версии libС++).
Ответ 2
Вопрос звучит наизнанку. Вы определяете тип с помощью std::function
, чтобы описать, как вы собираетесь называть объекты этого типа и каково их возвращаемое значение. Затем вы можете использовать эту специализацию std::function
для переноса различных вызываемых объектов, включая lambdas, которые имеют разные типы аргументов или другой тип возвращаемого значения.