0

I have the following code:

// For each trigger model (_1) (which is just a CString), do:
//    m_triggers.push_back(triggers.GetTrigger(static_cast<char const*>(_1)))
boost::transform(
   model.Triggers(),
   std::back_inserter(m_triggers),
   phx::bind(&CTriggerController::GetTrigger, phx::ref(triggers),
      phx::static_cast_<char const*>(_1)));

m_triggers is a vector of pointers to trigger objects:

std::vector<CTrigger*> m_triggers;

If the call to CTriggerController::GetTrigger() returns NULL (which means no trigger by that name could be found), I do not want to push anything to my m_triggers vector.

Is there a straightforward way of doing this through some minor modification to my code above?

I'm using Boost 1.55.0 on MSVC9 (C++03 only)

void.pointer
  • 24,859
  • 31
  • 132
  • 243
  • Just use an if statement to check the value, if it's not null, push to vector. – OMGtechy Mar 31 '14 at 19:30
  • I have been wishing for a `transform_if` on several occasions, but in most cases it turned out that excluding the edge case early on is just better. In your case, why would it be an acceptable case to have a `trigger` that is not in `GetTrigger`? It seems like this should be an invariant of your system, but I might be wrong. – pmr Mar 31 '14 at 20:55
  • I could make my own `back_inserter_if`, but I am not sure this is an elegant solution because I'm scattering predicate logic all over the place. – void.pointer Mar 31 '14 at 20:57
  • @pmr User input. If the trigger isn't there, but the data specifies it, the data is invalid. However, the system needs to be able to handle incorrect data. Simply ignoring input that doesn't yield a valid `CTrigger` is my way of recovering from that bad input. – void.pointer Mar 31 '14 at 20:58
  • Yes, you want a filtering output iterator ideally you can use `Boost.Range` http://stackoverflow.com/questions/7254131/is-it-possible-to-use-boostfilter-iterator-for-output – pmr Mar 31 '14 at 20:59
  • @pmr I have only seen filtering examples on the input container. Can you give an example of applying filtering to the 2nd parameter (the back_inserter)? – void.pointer Mar 31 '14 at 21:02
  • @RobertDailey I added an answer that does almost the same as the question I linked before. – pmr Mar 31 '14 at 21:14

2 Answers2

4

You can use Boost.Range to transform and filter at the same time.

#include <vector>
#include <iostream>

#include <boost/range.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>

int main()
{
  int data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  std::vector<int> out;
  using boost::adaptors::filtered;
  using boost::adaptors::transformed;
  boost::copy(data | transformed([](int x) { return x + 1; }) 
                   | filtered([](int x) { return x % 2 == 0; }),
              std::back_inserter(out));
  for(auto x : out) {
    std::cout << x << std::endl;
  }

  return 0;
}

And something that should fit your use-case better:

boost::copy(
   model.Triggers() | transformed(phx::bind(&CTriggerController::GetTrigger, phx::ref(triggers),
                        phx::static_cast_<char const*>(_1)))
                    | filtered(phx::val(phx::placeholders::_1)),
   std::back_inserter(m_triggers)
   );
pmr
  • 58,701
  • 10
  • 113
  • 156
  • Please note that as indicated in my question, I am using **C++03**. This won't work for me since it heavily uses C++11 features. – void.pointer Mar 31 '14 at 21:37
  • 1
    @RobertDailey This is sample code. Just replace the lambdas with your Phoenix expressions and everything is fine, the adaptors handle all `CallableS`. – pmr Mar 31 '14 at 21:40
  • What I'm telling you is that this is super misleading. I have zero experience with C++11 nor do I know how to translate your lambdas to the Phoenix equivalents. For the newbies, having a clear example will be most helpful and appreciated. – void.pointer Apr 02 '14 at 13:42
  • 2
    @RobertDailey There you go. I can't guarantee this is exactly what you need, because you don't provide a reproducible example, but it should be a good guess. – pmr Apr 02 '14 at 14:16
0

First copy to a temporary container using std:remove_copy_if with a predicate to remove when GetTrigger() == NULL, then transform.

stefaanv
  • 14,072
  • 2
  • 31
  • 53