Это должно произойти или просто недостаток в компиляторах?
Это должно произойти.std::function
имеет шаблон конструктора, который может принимать аргументы любого типа.Компилятор не может знать до тех пор, пока шаблон конструктора не будет выбран и создан, что он может столкнуться с ошибками, и он должен иметь возможность выбрать перегрузку вашей функции, прежде чем он сможет это сделать.
НаиболееПростое решение - использовать приведение или явно создать объект std::function
правильного типа:
func(std::function<void()>([](){}));
func(std::function<void(int)>([](int){}));
Если у вас есть компилятор, который поддерживает преобразование захвата-лямбды-функции-указателя и вашЛямбда ничего не захватывает, вы можете использовать необработанные указатели функций:
void func(void (*param)()) { }
void func(void (*param)(int)) { }
(Похоже, вы используете Visual C ++ 2010, который не поддерживает это преобразование. Преобразование не было добавлено в спецификацию донезадолго до поставки Visual Studio 2010, слишком поздно, чтобы добавить его.)
Чтобы объяснить проблему более подробно, рассмотрим следующее:
template <typename T>
struct function {
template <typename U>
function(U f) { }
};
Это в основномкак выглядит рассматриваемый конструктор std::function
: Вы можете вызывать его с любым аргументом, даже если аргумент не имеет смысламожет вызвать ошибку где-то еще.Например, function<int()> f(42);
будет вызывать этот шаблон конструктора с U = int
.
В вашем конкретном примере компилятор находит две функции-кандидата во время разрешения перегрузки:
void func(std::function<void(void)>)
void func(std::function<void(int)>)
Тип аргумента,какое-то необъяснимое имя лямбда-типа, которое мы будем называть F
, не соответствует ни одному из них в точности, поэтому компилятор начинает смотреть, какие преобразования он может сделать в F
, чтобы попытаться привести его в соответствие с одной из этих функций-кандидатов,При поиске конверсий он находит вышеупомянутый шаблон конструктора.
Все, что компилятор видит в этой точке, это то, что он может вызывать любую функцию, потому что
- он может преобразовать
F
в std::function<void(void)>
, используя конструктор преобразования с U = F
и - он может конвертировать
F
в std::function<void(int)>
, используя конструктор преобразования с U = F
.
В вашем примере очевидно, что только один из них будет выполнен без ошибок, нов общем случае это не так.Компилятор не может ничего сделать дальше.Он должен сообщить о неоднозначности и потерпеть неудачу.Он не может выбрать одно, потому что оба преобразования одинаково хороши, и ни одна перегрузка не лучше, чем другое.