3

Can we use a constructor as predicate? So far what I manage to be able to do is this:

std::vector<const char*> v1 = {
    "Hello", "from", "GCC", __VERSION__, "!"
};
std::vector<std::string> v2(v1.size());
std::transform(v1.begin(), v1.end(), v2.begin(),
    [] (const char* s) { return std::string(s); });

But I want some way to do std::tranform( ..., std::string). I've tried std::string::string, std::string::basic_string and std::string::basic_string<char>.

  • 6
    You can't do that with constructors. Why not just `vector v2(v1.begin(), v1.end())`? – David G Dec 25 '14 at 16:54
  • I also don't see a point for the use of `std::transform` in your question, are you actually having a XY-problem? – πάντα ῥεῖ Dec 25 '14 at 17:01
  • Pass the typename to a template, and use the typename to call the constructor? – Michael Gazonda Dec 25 '14 at 17:14
  • @πάντα ῥεῖ Can we assume that the user simplified their code and that although we can't see the "need" here that it may still be there? – Michael Gazonda Dec 25 '14 at 17:15
  • @MichaelGazonda That's why I've been asking about the XY-problem. – πάντα ῥεῖ Dec 25 '14 at 17:16
  • 1
    I think you mean functor not predicate; a predicate returns a bool. – Alan Stokes Dec 25 '14 at 17:35
  • 1
    This isn’t a predicate. A [predicate](http://stackoverflow.com/q/3230944/1968) is a filter criterion. Specifically, it’s a function which takes one argument and returns a `bool`. – Konrad Rudolph Dec 25 '14 at 17:36
  • @KonradRudolph: You probably mean a value contextually convertible to `bool`. Because it needn't actually be `bool`. – Deduplicator Dec 25 '14 at 17:37
  • 2
    @Deduplicator Maybe that’s philosophical but I maintain that a true predicate (in CS) needs to return a boolean value, and that some functions simply perform this conversion for you. In the context of C++, it’s true that they neither need to be a function, nor that they need to return a `bool` and furthermore, the standard even knows something known as a “binary predicate”, which I find an odd extension of the term. – Konrad Rudolph Dec 25 '14 at 17:42

3 Answers3

7

I would just do:

std::vector<std::string> v2(v1.begin(), v1.end());
Chris Drew
  • 14,926
  • 3
  • 34
  • 54
  • 1
    The easiest and simplest, which should be preferred until and unless some transformation is needed. In which case the range-for would win. – Deduplicator Dec 25 '14 at 17:38
1

Just do a simple

std::vector<std::string> v2;
v2.reserve(v1.size()); // Not really needed
for(auto x : v1) v2.emplace_back(x);
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • I heard that range-for loops cannot add contents to container. – wingerse Dec 25 '14 at 17:12
  • 2
    They can. But if you are in a range-for-loop over a container, you 1) don't know which index the current element has and 2) must not invalidate the containers iterators, as range-for is iterator-based. – Deduplicator Dec 25 '14 at 17:15
  • C++ Primer. Maybe my memory is not well. – wingerse Dec 25 '14 at 17:16
  • @EmpereurAiman Well it's not true. As Deduplicator said they can add elements but they are not without their pitfalls. – David G Dec 25 '14 at 17:20
  • @Deduplicator You probably want to move the elements in: `v2.emplace_back(std::move(x))`. – David G Dec 25 '14 at 17:22
  • Ok thanks @Deduplicator and @0x499602D2!, I probably need to do actual programming without just reading books :) – wingerse Dec 25 '14 at 17:23
  • @0x499602D2: In this case, I don't actually want to move. In general, it's a worthwhile optimization though. – Deduplicator Dec 25 '14 at 17:25
0

The trick is that we need to pass the typename to a template, and then we can use that to call the constructor that you want.

Here's what I've come up with:

template<typename source, typename destination, typename iter, typename iter2>
void transform_object(iter begin, iter end, iter2 begin2)
{
    std::transform(begin, end, begin2, [](source s){ return destination(s); } );
}

And to use it with your original code:

transform_object<const char*, std::string>(v1.begin(), v1.end(), v2.begin());
David G
  • 94,763
  • 41
  • 167
  • 253
Michael Gazonda
  • 2,720
  • 1
  • 17
  • 33
  • 1
    Why the struct with the static method? You can make it a free function template, you can also get the element type with `typename iter::value_type`. – David G Dec 25 '14 at 17:26
  • @0x499602D2 Fixed. Was getting used to structs for everything... ty for the catch. – Michael Gazonda Dec 25 '14 at 17:29