1

I am trying to create a class Vec and it contains method map to return an new Vec odject. I want map method can return different type (like Javascript's map function).

The error is found:

main.cpp:31:13: error: no matching member function for call to 'map'
    numbers.map([](int &item)
    ~~~~~~~~^~~

main.cpp:18:12: note: candidate template ignored: couldn't infer template argument 'U'
    Vec<U> map(Lambda lambda)

Here is my code:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

template <typename T>
class Vec
{
public:
    std::vector<T> value;

    Vec(std::vector<T> vector)
    {
        value = vector;
    }

    template <typename Lambda, typename U>
    Vec<U> map(Lambda lambda)
    {
        std::vector<U> updatedValue;
        std::transform(value.begin(), value.end(), std::back_inserter(updatedValue), lambda);
        Vec<U> UpdatedVector(updatedValue);
        return UpdatedVector;
    }
};

int main()
{
    Vec<int> numbers({10, 20, 30, 40, 50});

    Vec<std::string> new_numbers = numbers.map([](auto &item)
                                               { return "new value is string"; });

    // Value of the 'new_numbers.value' should be {"new value is string", "new value is string", "new value is string", "new value is string", "new value is string"}

    return 0;
}
kelvinwong
  • 103
  • 5
  • 3
    The compiler has no way of knowing what `U` is when you call `Vec::map` – Jason Jun 26 '22 at 04:41
  • 1
    You might be looking for something like `template ()(*value.begin()))>...` Except that your `lambda` returns a `char*`, but you expect to assign the result to `Vec` – Igor Tandetnik Jun 26 '22 at 04:44
  • This also almost appears to be an attempt to extend a `std::` collection class via inheritance. https://stackoverflow.com/questions/4353203/thou-shalt-not-inherit-from-stdvector – selbie Jun 26 '22 at 04:46
  • You can make it work [like this](https://godbolt.org/z/q66E4TTK1) – Igor Tandetnik Jun 26 '22 at 04:50

1 Answers1

0

In C++ you can't specialize functions on return type and this is also true for function templates. To specialize on template value you need explicitly specialize your function template return value like this:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>

template <typename T>
class Vec
{
public:
    std::vector<T> value;

    Vec(std::vector<T> vector)
    {
        value = vector;
    }

    // I reversed the order of the template arguments here
    template <typename U, typename Lambda>
    Vec<U> map(Lambda lambda)
    {
        std::vector<U> updatedValue;
        std::transform(value.begin(), value.end(), std::back_inserter(updatedValue), lambda);
        Vec<U> UpdatedVector(updatedValue);
        return UpdatedVector;
    }

    auto& values() const noexcept
    {
        return value;
    }
};

int main()
{
    Vec<int> numbers({ 10, 20, 30, 40, 50 });

    // NOTE the explicit target type to convert to in map function template call
    Vec<std::string> new_numbers = numbers.map<std::string>([](const auto& item) 
    { 
        return std::to_string(item); 
    });

    for (const auto& value : new_numbers.values())
    {
        std::cout << value << "\n";
    }

    return 0;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19