Reputation: 2060
Why the following class A
can't deduce its template parameters in the code below:
#include <functional>
template <class... Ts>
class A
{
public:
using Func = std::function<void(std::decay_t<Ts>...)>;
A(Func func) : m_func(func)
{
}
private:
Func m_func;
};
int main()
{
//compiles
A<int, bool> a([](int, bool) {});
//does not compile with error 'class template argument deduction failed'
A b([](int, bool) {});
return 0;
}
The class have a data member of type Func
and needs to know the types of its parameters. How to make it compile?
EDIT1:
I was able to make this compile with std::tuple
:
#include <tuple>
template <class... Ts>
class A
{
public:
using Func = std::tuple<Ts...>;
constexpr A(Func func) : m_func(func)
{
}
private:
Func m_func;
};
int main()
{
std::tuple<int, bool> t;
//compiles
A<int, bool> a(t);
//do not compile with error 'class template argument deduction failed'
A b(t);
return 0;
}
Upvotes: 2
Views: 1000
Reputation: 173024
Two issues.
Implicit conversion (from lambda to std::function
) won't be considered in template argument deduction; which causes deduction failing.
The existence of std::decay_t
results in non-deduced context; then Ts
can't be deduced.
The following code compiles.
#include <functional>
template <class... Ts>
class A
{
public:
using Func = std::function<void(Ts...)>;
A(Func func) : m_func(func)
{
}
private:
Func m_func;
};
int main()
{
//compiles
A<int, bool> a([](int, bool) {});
//compiles
A b(std::function([](int, bool) {}));
return 0;
}
Upvotes: 1
Reputation: 10614
Template parameter deduction traditionally was an exclusive feature of a function call expression. Template parameters of a class template could not be deduced from a constructor call until the introduction of deduction guides in C++17. With that, you can explicitly specify how template parameters of a class should be deduced from a constructor call.
template <class... Ts>
class A
{
public:
using Func = std::tuple<Ts...>;
constexpr A(Func func) : m_func(func)
{
}
private:
Func m_func;
};
template< class... Ts >
A(std::tuple< Ts... >) -> A< Ts... >;
int main()
{
std::tuple<int, bool> t;
A<int, bool> a(t);
A b(t); // deduces int, bool types from t
return 0;
}
The use of a deduction guide to deduce a function call signature from a lambda can be problematic. The lambda function does not define a type that corresponds to its signature. If the lambda is polymorphic (i.e. uses auto
in its argument list) then such type is not possible to define in the first place. And a function can be called with arguments different from its signature, so there may be multiple different sets of argument types, with which the function is callable. You will most likely have to specify the parameter types explicitly in this case.
Deducing template parameters from function pointers is still possible, though:
template< class R, class... Ts >
A(R (*)(Ts...)) -> A< Ts... >;
Upvotes: 0