Use of functor within transformation

What would be the point of defining constructor methods within the class below?
The output of the called functor within the transformation in the main function is the same irrespective of the user-defined constructors.
A course on templates and the STL utilizes this code as an example of transformations but the constructors are included, which I think are unnecessary.
The objective of the functor is to capitalize the first character in each string passed but it would not function properly based on the implementation herein if the constructor methods are actually utilized/called.


#include <cctype>

class title_case {
char _last;
char _sep = 0;
public:
// title_case() : _last(0) {}
// title_case(const char c) : _last(1), _sep(c) {}
const char operator() (const char c);
};

const char title_case::operator() (const char c) {
// if(_sep) _last = (!_last || _last == _sep) ? toupper(c) : c;
_last = (!_last || isblank(_last)) ? toupper(c) : c;
return _last;
}



int main()
{
string s1 = "this is a string";
cout << s1 << endl;

string s2(s1.size(), '.');
transform(s1.begin(), s1.end(), s2.begin(), title_case());

cout << s2 << endl;

return 0;
}
Is the _last properly initialized?
¿what was the original code?
`_sep' is not used, you call to `isblank()' instead
1
2
//title_case(';')
"hello;brave new;world" -> "Hello;Brave new;World"

The default constructor is called once (and _last initialized) if the commented code is included, so the parametrized constructor and _sep are not utilized. The code runs fine without the constructors and the if statement but apparently that may cause UB?
Are there scenarios where the parametrized constructor and the functor would be called simultaneously or sequentially?
Last edited on
Yes, Undefined Behaviour.

With no explicit constructors, the class has implicit default constructor.
The _last has no initializer and is therefore default initialized (with undetermined value) by the default constructor.
The _sep has default initializer and has thus value 0 after construction.

The (first call to) operator() uses the undetermined _last and therefore its result is UB.


If you add the custom constructor title_case(const char), then no default constructor will be created automatically.
In order to have both, you need to define the default constructor.

Are there scenarios ..?

Yes. You might need to:
1
2
transform( s1.begin(), s1.end(), s2.begin(), title_case() );
transform( s1.begin(), s1.end(), s3.begin(), title_case(';') );
How would one pass the functor by reference? It seems the STL algorithms prefer function objects be passed by value?
How would one pass the functor by reference?

Pass std::ref(my_functor).

Be careful not to assume too much about what the library does with your function object. In particular, do not rely on order of application.
Last edited on
Yes I noticed the copy constructor is called when the transform algorithm is called but wanted to find a way to prevent this from occurring so the state of the object instance that is passed is modified directly.

I'm getting namespace std has no member ref.
I'm getting namespace std has no member ref.

The appropriate cppreference page will tell you the header file that declares std::ref, and which C++ standard version introduced it:
https://en.cppreference.com/w/cpp/utility/functional/ref
To summarize, it's part of the <functional> header since C++11.

mbozzi wrote:
Be careful ...
darnoceloc wrote:
I noticed the copy constructor is called when the transform algorithm is called but wanted to find a way to prevent this from occurring so the state of the object instance that is passed is modified directly.

I only suggest general caution. It's a relatively common error to assume too much about what (any) library does with a stateful function object.
Last edited on
Why does std::ref need to be used in this scenario, why can’t the standard reference assignment identifier be used to create a reference to the function object and pass it to the transform algorithm. Would the algorithm create a copy of that function object reference that does not also reference the original object function object that was passed by reference?

I’ve seen examples in which a separate state class was defined outside of the function class then declared as a member variable of the function class. The constructor of the function class is then defined to take a reference object to the state class as a parameter which is utilized to initialize the state object that was already declared as a member variable. Essentially passing the state object by reference ‘inside’ the function object.
Why does std::ref need to be used in this scenario, why can’t the standard reference assignment identifier ...


What is the "standard reference assignment identifier"?

When you call a template, like:
1
2
3
template <class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator std::transform( InputIterator, InputIterator,
                               OutputIterator, UnaryOperation );

the compiler deducts type UnaryOperation from the type of the parameter. The deduction rules are in the standard.
By ‘standard reference identifier’ I mean, declaring Funct &obj prior to call of algorithm , then pass obj to std. algorithm. Instead of declaring Funct obj, then passing std::ref(obj). What is the difference in those two approaches, is it due to the copy-constructible and copy-assignable attributes of the reference wrapper?
You've fallen for a common misconception: "my code works, therefore it is correct."
The truth is that your code works by accident, not by design.

_last is uninitialized, so it could contain any value that happens to be there. If it contained anything but zero, the first character would not be capitalized.
I mean, declaring Funct &obj prior to call of algorithm.

There's no possible way to do anything with or learn anything about a reference itself. All operations performed to a reference are applied to the referenced object:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Funct f1;
Funct& rf1 = f1; // must initialize

Funct& rf2 = rf1; // rf1 is indistinguishable from f1
// rf1 and rf2 name the same object

Funct f2 = rf2; // rf2 is indistinguishable from f1
// f2 is a copy of f1.

// size of a reference is the size of the referent
static_assert(sizeof (char&) == sizeof (char));
static_assert(sizeof (f1) == sizeof (rf2));
// address of a reference is the address of the referent
assert(&rf1 == &f1);
// etc. 


This is why the proposed solution won't work: C++'s reference variables are referentially transparent. References merely assign a new name to the referenced object; there is no way to do anything with the reference itself. Attempting to copy it will copy the referenced value.

std::ref returns a reference_wrapper. The standard library will copy that reference_wrapper however much it wants. However, each copy still refers to the same function object.

We would say that std::reference_wrapper does not maintain value semantics because it makes object identity important.
Last edited on
So the reference is essentially just another alias via which a value can be accessed but the reference wrapper class (emulator of aforementioned reference) allows the alias to be copied instead of the value being referred.
Yes.
Or, in other words, the reference is only move assignable while the reference wrapper is copy assignable and copy constructible.
Not so. A reference to title_case behaves identically to the title_case it aliases. Every title_case is copy/move-constructible and copy/move-assignable.

The standard provides complete referential transparency. References do nothing but alias existing objects, every operation on a reference operates on the aliased object. Attempting to move from a reference will attempt to move from the referenced value.

The distinction between move/copy isn't very relevant here.

std::reference_wrapper can be copy-constructed and copy-assigned, but instead of copy-constructing or copy-assigning the stored object, it copies a pointer (typically a pointer) to the object it refers to.

The effect is that distinct copies of reference_wrapper<title_case> refer to the same title_case with the same internal state, whereas distinct copies of title_case are independent objects with duplicate internal state.
Last edited on
Okay, that clears it up. The alias cannot be reassigned once it’s bound to the object it’s referencing which further validates your point.
Topic archived. No new replies allowed.