I'm trying to implement a class which is an iterator across a linked-list. I want to templatize it so you can construct it with a functor to determine when we are iterating to the end, but I can't get the class constructor template deduction to deduce the type of the functor.
A reduced example of what I'm trying to do:
#include <utility>
struct A {};
struct B : A {};
template<typename T, typename F>
struct C
{
A * a_;
F f_;
C(A * a, F && f) : a_(a), f_(std::move(f)) {}
T & operator*() { return static_cast<T &>(*a_); }
};
int main()
{
B b;
C<B> foo(&b, [b]() -> bool { return false; }); // error: wrong number of template arguments (1, should be 2)
return 0;
}
I always get the template argument error when trying to instantiate an object (compiling with c++17), strangely godbolt gives me these cryptic ones too: error: expression list treated as compound expression in initializer [-fpermissive]
and error: cannot convert 'main()::<lambda()>' to 'int' in initialization
which makes no sense, but might just be fallout from the first error.
Shouldn't it be able to deduce the functor type F
from the constructor arguments? Am I doing something wrong here?
For CTAD to work you can't supply any of the template parameters and since T
can't be deduced, you need to supply the second template parameter too (that is, no CTAD).
Example:
auto l = [b]() -> bool { return false; };
C<B,decltype(l)> foo(&b, std::move(l));
You could add a helper function template though:
template<typename T, typename F>
auto C_creator(A* a, F&& f) { return C<T,F>(a, std::forward<F>(f)); }
auto foo = C_creator<B>(&b, [b]() -> bool { return false; });
Or change the constructor to take a T*
instead of an A*
so that T
can be deduced.
C(T* a, F&& f) : a_(a), f_(std::move(f)) {}
auto foo = C(&b, [b]() -> bool { return false; });