Проблема в том, что значение, возвращаемое std::bind
, может быть преобразовано в std::function
, но не std::function
.
Это своего рода проблема с яйцом и курицей.
Когда вы вызываете
EnumToVec<float>(std::bind(EnumerateFoo, 3.14f, _1, _2));
, вы получаете то, что компилятор не может выбирать между void
и int
версией, потому что EnumVec
не получает значение std::function
;и не получает std::function
, потому что компилятор не может выбирать между void
и int
версией.
Возможное решение - явно создать правильный std::function
и вызов EnumToVec
std::function<int(uint32_t *, float *)> ef { std::bind(EnumerateFoo, 3.14f, _1, _2) };
auto vecFoo = EnumToVec(ef);
Заметьте, что вы можете избежать явного указания параметра шаблона float
, поскольку он может быть выведен с помощью ef
.
Еще одно возможное решение - отдать std::function
, получитьисполняемый файл как универсальное имя типа и SFINAE включают / отключают две функции в соответствии с типом, возвращаемым функционалом
Что-то как
template <typename T, typename F>
auto EnumToVec (F const & fn)
-> std::enable_if_t<std::is_same_v<
decltype(fn(std::declval<std::uint32_t*>(), std::declval<T*>())),
int>, std::vector<T>>
{ //....^^^ int here
vector<T> ret;
uint32_t count = 0;
if(fn(&count, nullptr))
return vector<T>();
ret.resize(count);
if(fn(&count, ret.data()))
return vector<T>();
return ret;
}
template <typename T, typename F>
auto EnumToVec (F const & fn)
-> std::enable_if_t<std::is_same_v<
decltype(fn(std::declval<std::uint32_t*>(), std::declval<T*>())),
void>, std::vector<T>>
{ // ...^^^^ void here
vector<T> ret;
uint32_t count = 0;
fn(&count, nullptr);
ret.resize(count);
fn(&count, ret.data());
return ret;
}
Так что вы можете вызвать
auto vecFoo = EnumToVec<float>(std::bind(EnumerateFoo, 3.14f, _1, _2));
но объясняя T
имя типа, потому что не выводится.