简体   繁体   中英

3d vectors - transform and minus

Can std::transform be used in a nested way? Tried to do this:

                    {
                        return std::transform(asciivec(inner.front()).begin(), asciivec(inner.front()).end(), asciivec(inner.back()).begin(), asciivec(inner.back()).end(),out.begin(), std::minus<float>{});
                    }
                   );
Error: 
stl_algo.h||In instantiation of '_OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation) [with _IIter = __gnu_cxx::__normal_iterator<const std::vector<std::__cxx11::basic_string<char> >*, std::vector<std::vector<std::__cxx11::basic_string<char> > > >; _OIter = __gnu_cxx::__normal_iterator<double*, std::vector<double> >; _UnaryOperation = main()::<lambda(const auto:1&)>]':|


error: no matching function for call to 'transform(std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, std::minus<float>)'|

You were on the right track, but you missed a few things.

  • For binary operations, std::transform only takes both begin and end iterators for the first input range; it takes a begin iterator for the second range, and assumes the second range is at least as large as the first (such that for any element in the range [first1, last1) , there's a matching element in the range starting at first2 ).

  • Assuming that asciivec() returns a temporary object (and not a reference to a cached object), the iterators asciivec(inner.front()).begin() and asciivec(inner.front()).end() will actually refer to two different ranges; this will cause runtime errors. You'll need to cache the results of your asciivec() calls inside the lambda, to give them enough permanence to finish the operation.

  • std::minus evaluates its operands as lhs - rhs , and thus will return -1 for std::minus<float>{}('a', 'b') . As your example results are positive, I have assumed you want absolute values, and have expanded & commentated my code thusly.

So, considering that, we can make a few slight alterations...

// Renamed "inner" to "in" for convenience here.
std::transform (inp.cbegin(), inp.cend(), out.begin(), [&](const auto& in)
    {
        // Tying element type to asciivec() for convenience.
        using Container = decltype(asciivec(in.front()));
        using      Elem = typename Container::value_type;
        //using Elem = typename decltype(asciivec(in.front()))::value_type;

        // Create non-temporary vectors first, to guarantee expected results.
        std::vector<Container> inner = { asciivec(in.front()), asciivec(in.back()) };

        // Use either...
        // static Container ret;
        // ret.clear(); ret.resize(inner.front().size());
        // Or...
        Container ret(inner.front().size());

        std::transform(inner.front().begin(),          // InputIt first1
                       inner.front().end(),            // InputIt last1
                       inner.back().begin(),           // InputIt first2
                       //asciivec(inner.back()).end(), // Omit
                       ret.begin(),                    // OutputIt d_first
                       std::minus<float>{});           // BinaryOperation binary_op

        // I'm positive you want absolute values. ;3
        // Lambda provides nice, clean overload resolution, compared to a function pointer or similar.
        std::transform(ret.begin(), ret.end(), ret.begin(), [=](const Elem& e) { return std::fabs(e); });

        return ret;
    }
);

If signedness is, in fact, desired, we can comment out the second transform() call.

See it in action here .

Edited to increase genericity, it should be fine to just drop in regardless of your data's actual types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM