2

Let's say I have this function:

template <typename T> T sum(std::vector<T> const& v) { T acc = T(); for (auto const& e : v) { acc += e; } return acc; } 

Here C++ only allows to call this function with vectors, and can automatically infer the T type parameter.

Is there any way I could do the same using lambdas? I know they are semantically same as a functor and I could easily do that there, but I'm interested in lambdas inline. I know I can do this:

[](auto& v) { ... } 

But this matches anything, even non-vector parameters (even if the body causes a compiler error).

2
  • 6
    Coming in C++20 :) Commented Jan 5, 2018 at 16:27
  • @Quentin That's kind of disappointing, I need workarounds again. Thank you for the info! Commented Jan 5, 2018 at 16:36

2 Answers 2

1

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; }; 

Demo

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; } 

Demo for any iterable container with a value_type

Demo with static_assert for vector type


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{}; // ... }; 
Sign up to request clarification or add additional context in comments.

7 Comments

This would be nice for this exact problem, but I actually have to deal with phantom types in sum-types, this is not a viable solution. Sorry, I brought a wrong example, I should have asked more general I guess.
@PeterLenkefi: I don't understand why you are summing phantom types?
My problem is actually pretty complicated, I could explain in chat if you are interested.
@PeterLenkefi: No worries, it's probably outside the scope of the question. Still, I'd hope that maybe you could add a type trait to your phantom type, like using value_type = PHANTOM_TYPE?
@PeterLenkefi: You don't necessarily need to add it directly to your phantom type class either, you could use a separate traits specialization like so: wandbox.org/permlink/Zcgp5ZsUuEuX81OS
|
0

You could use a lambda with std::accumulate, although given a simple sum there wouldn't actually be a need for the lambda.

1 Comment

Sure, that was an example. I'm interested in matching overload sets.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.