0

I am trying to get a bit of practice with std::transform by using it to decrypt a simple Caesar cypher. But apparentrly my function definition is wrong, since the compiler considers the unary function argument invalid. Here is my code:

char CryptoModule::UndoCaesar(char& letter)
{
    return (letter - atoi(key_.c_str()) % 128);
}

void CryptoModule::DecryptCaesar()
{
    std::transform(data_.begin(), data_.end(), data_.begin(), UndoCaesar);
}

Could anyone please tell me where the error lies ? In addition, what would I need to modify in order to use for_each ? I believe it would involve changing the return value to a void and storing the result in letter.

Thanks and have a nice day

Edit: Tried adding bind, but still not working. Current call is :

std::transform(data_.begin(), data_.end(), data_.begin(), bind(&UndoCaesar, this, std::placeholders::_1));
Bruno Ayllon
  • 75
  • 1
  • 5

1 Answers1

10

Your given member function has a hidden this parameter, so you need to bind that in order to pass it:

std::transform(data_.begin(), data_.end(), data_.begin(), 
    std::bind(&CryptoModule::UndoCaesar, this, std::placeholders::_1)
);

Note that std::bind is in <functional>. All this does is basically cause std::transform to call whatever function-like object, f, it takes like f(currentElement) and have that in turn call UndoCaesar(this, currentElement) with this being part of its state because you bound it.

Alternatively, you can wrap the call in a lambda that captures this so that it can be used for the member function call (implicitly, like normal):

std::transform(data_.begin(), data_.end(), data_.begin(), 
    [this](char c) {return UndoCaesar(c);}
);
chris
  • 60,560
  • 13
  • 143
  • 205
  • It still seems to think that I have a missing argument list. By the way, where did the hidden this parameter come from ? – Bruno Ayllon Feb 23 '14 at 07:49
  • 2
    @BrunoAyllon, It's a member function. Member functions need an object to operate on. Could you be more specific with your error? Here's a [working example](http://coliru.stacked-crooked.com/a/2ee773ba03163499). – chris Feb 23 '14 at 07:49
  • Directly from Visual Studio :error C3867: 'CryptoModule::UndoCaesar': function call missing argument list; use '&CryptoModule::UndoCaesar' to create a pointer to member c:\users\bruno\documents\mat258\encryption\encryption\cryptomodule.cpp 85 1 Encryption – Bruno Ayllon Feb 23 '14 at 07:53
  • 1
    @BrunoAyllon, Does your code have the ampersand in front of it? It's required for member function pointers, unlike normal functions, which will decay into function pointers when you just have their name. – chris Feb 23 '14 at 07:54
  • 1
    As an alternative, I would recommend we forget `std::bind` exists and use a lambda instead: `std::transform(data_.begin(), data_.end(), data_.begin(), [this](char c) { return UndoCaesar(c); })` – Benjamin Lindley Feb 23 '14 at 07:56
  • @BenjaminLindley, Also a good suggestion. I'll add that to the answer as an alternative. – chris Feb 23 '14 at 07:57
  • The lambda seems to work, but I am not very familiar with them. Seem to be similar to calling function pointers. But what does the data inside the [] mean in the syntax ? – Bruno Ayllon Feb 23 '14 at 08:02
  • @BrunoAyllon, Your current error is because member function pointers require the class name as well: `&ClassName::MemberFunctionName`. As another note, `UndoCaesar` does not (and should not if being used with `std::transform`) modify `c`, so it should be passed by value, and does not modify the object's state, so it should be marked `const`. – chris Feb 23 '14 at 08:03
  • @BrunoAyllon, There's a nice explanation of lambdas [here](http://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11/7627218#7627218). The `[this]` just means it's capturing `this` so it can use it inside the body. Although you don't see it used, it still is implicitly, as if to say `this‑>UndoCaesar(c);`. – chris Feb 23 '14 at 08:04
  • It worked for both lambdas and bind. Thank you all so much. Also thank you for the lambda function referrence. Is there anywhere I can read more about these special cases for transform ? – Bruno Ayllon Feb 23 '14 at 08:51
  • @BrunoAyllon, It's not a special case for just `std::transform`. It applies to a lot of algorithms and other functions that call something you pass in. It takes your function and assumes that it has one parameter - the current element - so it can use *any* function-like object that can be called with one argument. Now for where the trouble comes in (and for where you can find more information) is the member function, as it cannot just be called with one argument like other things because it needs an object. If looking for more, try searching how to use member functions in callbacks for plenty. – chris Feb 23 '14 at 09:08