In C++20, we can specify template arguments following the capture list:
auto accum = []<class T>(std::vector<T>& v) { auto acc = T{}; for (auto const& e : v) { acc += e; } return acc; };
In the interim suppose that for now you're stuck relying on type traits to infer value_type:
auto accum = [](auto& v) { auto acc = typename std::decay_t<decltype(v)>::value_type{}; for (auto const& e : v) { acc += e; } return acc; };
You could use a static_assert if you wanted to enforce particular container(s):
auto accum = [](auto& v) { using ttype = std::decay_t<decltype(v)>; using vtype = typename ttype::value_type; static_assert(std::is_same_v<std::vector<vtype>, ttype>); auto acc = vtype{}; for (auto const& e : v) { acc += e; } return acc; };
For example:
int main(){ std::vector<int> v{1,2,3}; std::list<double> l{4.0,5.0,6.0}; auto accum = [](auto& v) { auto acc = typename std::decay_t<decltype(v)>::value_type{}; for (auto const& e : v) { acc += e; } return acc; }; std::cout << accum(v) << std::endl; std::cout << accum(l) << std::endl; }
Since you mentioned that you are not using STL containers, but rather Phantom Types, then you have two options:
- Add a typedef to your strongly-typed enum like so
using value_type = PHANTOM_TYPE Create a separate traits class to infer value_type:
template struct SUInt { public: SUInt (unsigned int value) : m_value(value) { } inline unsigned int& Value () { return m_value; } private: unsigned int m_value; };
template struct SUInt_traits{};
template struct SUInt_traits>{ using value_type = T; };
Which you can then use from within your lambda like so:
auto do_a_thing = [](auto& v) { auto acc = typename SUInt_traits<std::decay_t<decltype(v)>>::value_type{}; // ... };