6

I would like to create a vector of pairs starting from a pair of vectors. For example, if A is std::vector A = [1 0 1] and B is std::vector B = [0 1 0], I want a structure std::vector C = [1 0, 0 1, 1 0] where C_i = std::pair(A_i,B_i).

I would avoid for loop through the two vector, so I'm looking for few lines code like std::transform().

I tried the following code:

std::vector<bool> boolPredLabel(tsLabels.size()); 
std::vector<bool> boolRealLabel(tsLabels.size());
std::vector<std::pair<bool,bool>> TrPrPair(tsLabels.size());
std::transform(boolRealLabel.begin(), boolRealLabel.end(), boolPredLabel.begin(), TrPrPair.begin(),std::make_pair());

This lead me to a compiler error:

error: no matching function for call to ‘make_pair()’
std::transform(boolRealLabel.begin(), boolRealLabel.end(), boolPredLabel.begin(), TrPrPair.begin(),std::make_pair());
...
note:   candidate expects 2 arguments, 0 provided
std::transform(boolRealLabel.begin(), boolRealLabel.end(), boolPredLabel.begin(), TrPrPair.begin(),std::make_pair());

The message is clear, but I don't know what pass to the binary operator. I have to admit that I don't have a clear understanding of std::transform() and I've just use it with functor.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Luca Jungla
  • 150
  • 8
  • 1
    You need to give the template types for `make_pair`. `std::transform(... , std::make_pair);` https://ideone.com/i9aV3Y – Retired Ninja May 03 '19 at 19:27
  • @RetiredNinja You should post that as an answer, it's better than mine. – lubgr May 03 '19 at 19:29
  • @lubgr Nah, but you may incorporate that into yours. I was surprised it worked too. :) – Retired Ninja May 03 '19 at 19:29
  • [boost::make_zip_iterator](https://www.boost.org/doc/libs/1_70_0/libs/compute/doc/html/boost/compute/make_zip_iterator.html) might interest you. – Jarod42 May 03 '19 at 19:57
  • @lubr Thanks for the useful answers. The problem is solved but I still confused about the binary operation of make_pair. How can I check that a specific function object or template function has the appropriate signature function? – Luca Jungla May 04 '19 at 10:00
  • 1
    Good question. You can only figure it out from context and docs. In this case: "The types Type1 and Type2 must be such that objects of types InputIt1 and InputIt2 can can be dereferenced and then implicitly converted to Type1 and Type2 respectively. [...]" So its all about dereferencing the iterators. For two `std::vector` (input) and a `std::vector>` (output), the input derereferences to something `bool`-like and the output to `std::pair`. Hence the signature `std::pair f(bool, bool)`or `std::pair f(const bool&, const bool)`. – lubgr May 04 '19 at 20:33
  • Also note that `std::vector` is a bit special here, as it's a template specialization that stores a compact form of a boolean representation. This is commonly understood as a design mistake. If you're interested in some more details, see e.g. [this thread](https://stackoverflow.com/questions/17794569/why-is-vectorbool-not-a-stl-container). – lubgr May 04 '19 at 20:37

1 Answers1

7

The binary operation you pass in doesn't make any sense. std::make_pair is a function template taking two arguments, so neither can you invoke it without these two arguments, nor can it be instantiated like a function object to be passed to std::transform.

Instead, you can explicitly instantiate std::make_pair for the template types in question and pass this as to the algorithm (@RetiredNinja pointed that out but apparently felt too lazy to write an answer):

std::transform(boolRealLabel.cbegin(), boolRealLabel.cend(),
    boolPredLabel.cbegin(), TrPrPair.begin(), std::make_pair<bool, bool>);

Two other options commonly seen are a lambda,

std::transform(boolRealLabel.cbegin(), boolRealLabel.cend(), boolPredLabel.cbegin(),
    TrPrPair.begin(), [](bool a, bool b){ return std::make_pair(a, b); });

or a pointer to a function

std::pair<bool, bool> toPair(bool a, bool b)
{
    return std::make_pair(a, b);
}

std::transform(boolRealLabel.cbegin(), boolRealLabel.cend(),
    boolPredLabel.cbegin(), TrPrPair.begin(), toPair);

And for completeness, cppreference on std::transform and its binary operation argument (only relevant to the overload that acts on two input ranges):

binary_op - binary operation function object that will be applied.

The signature of the function should be equivalent to the following:

Ret fun(const Type1 &a, const Type2 &b); 
Community
  • 1
  • 1
lubgr
  • 37,368
  • 3
  • 66
  • 117