I wanted to implement a overload for operator<<
that allowed me to call a given function and output the result.
I therefore wrote an overload, but the conversion to bool is selected and when writing a function myself, it would not compile.
EDIT: Know that I do not want to call the lambda, but instead pass it to the function where it should be called with a default constructed parameter list.
I have appended my code:
#include <iostream>
template<typename T>
void test(T *) {
std::cout << "ptr" << std::endl;
}
template<typename T>
void test(bool) {
std::cout << "bool" << std::endl;
}
template<typename Ret, typename ...Args>
void test(Ret(*el)(Args...)) {
std::cout << "function ptr\n" << el(Args()...) << std::endl;
}
template<typename Char_T, typename Char_Traits, typename Ret, typename ...Args>
std::basic_ostream<Char_T, Char_Traits>& operator<<(
std::basic_ostream<Char_T, Char_Traits> &str, Ret(*el)(Args...)) {
return str << el(Args()...);
}
int main() {
std::boolalpha(std::cout);
std::cout << []{return 5;} << std::endl; // true is outputted
test([]{return 5;}); // will not compile
}
I use gcc 7.3.1 with the version flag -std=c++14
.
EDIT: Error message:
main.cc: In function ‘int main()’:
main.cc:25:23: error: no matching function for call to ‘test(main()::<lambda()>)’
test([]{return 5;});
^
main.cc:5:6: note: candidate: template<class T> void test(T*)
void test(T *) {
^~~~
main.cc:5:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘T*’ and ‘main()::<lambda()>’
test([]{return 5;});
^
main.cc:9:6: note: candidate: template<class T> void test(bool)
void test(bool) {
^~~~
main.cc:9:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: couldn't deduce template parameter ‘T’
test([]{return 5;});
^
main.cc:13:6: note: candidate: template<class Ret, class ... Args> void test(Ret (*)(Args ...))
void test(Ret(*el)(Args...)) {
^~~~
main.cc:13:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘Ret (*)(Args ...)’ and ‘main()::<lambda()>’
test([]{return 5;});
Your problem here is that Template Argument Deduction is only done on the actual argument passed to test
. It's not done on all possible types that the argument could possibly converted to. That might be an infinite set, so that's clearly a no-go.
So, Template Argument Deduction is done on the actual lambda object, which has an unspeakable class type. So the deduction for test(T*)
fails as the lambda object is not a pointer. T
can't be deduced from test(bool)
, obviously. Finally, the deduction fails for test(Ret(*el)(Args...))
as the lambda object is not a pointer-to-function either.
There are a few options. You might not even need a template, you could accept a std::function<void(void)>
and rely on the fact that it has a templated constructor. Or you could just take a test(T t)
argument and call it as t()
. T
will now deduce to the actual lambda type. The most fancy solution is probably using std::invoke
, and accepting a template vararg list.