2

Looking at C++ interface code. I do not have access to the implementation. I made a small example to show the behavior.

struct MessageInfo{
    
    MessageInfo() : length{}, from{}, to{} {}
    
    MessageInfo(int _length, string _from, string _to) : length{_length}, from{_from}, to{_to} 
    {}

    int length;
    string from;
    string to;
      
    using IsEnumerableTag = void;
    template<typename F>
    void enumerate(F& fun) {
        fun(this->length);
        fun(this->from);
        fun(this->to);
     }
};

Can somebody explain to me what is the usage of enumerate struct function member in this struct definition?

Based on my understanding the enumerate in this struct can take a function type as input parameter (function pointer?)

  1. Does it mean that whenever we create an object of MessageInfo struct we can call this method like below?
  2. How can define the function type, In other words what should i use instead of "???" in following code?
  3. What is the advantage of this model of coding (more specifically about enumerate method)?
MessageInfo messageInfo (1000, "A", "B");
    
messageInfo.enumerate<???>(printFrom(messageInfo.From);
      
void printFrom(string f) {
     cout<<"the msgInfo is sent from "<<  f<<endl;
}
0

1 Answer 1

5

It expects you to pass a generic callable, e.g. a lambda. You don't have to specify the template argument. It can be deduced from the function argument.

For example:

MessageInfo messageInfo (1000, "A", "B");

auto printFields = [](auto&& f){ std::cout << "Value of this field is " << f << ".\n"; };

messageInfo.enumerate(printFields);

which should print

Value of this field is 1000.
Value of this field is A.
Value of this field is B.

As you can see from this, enumerate can be used to apply the same operation to every member without having to repeat yourself for each one.

The signature is a bit unusual. You would normally expect F or F&& instead of F&. With either F or F&& you could put the lambda expression directly into the call instead of having to store it in a variable first.

Sign up to request clarification or add additional context in comments.

3 Comments

"It expects you to pass a generic callable, e.g. a lambda" - generic lambdas exist in C++14 and later. For earlier versions, you can use a functor with overloaded operator() for each input type.
Thanks @user17732522 it was really helpful. Can you also explain to me why by using F& we cannot use directly the lambda function. As you mentioned I have tried it and got a compilation error, but it was resolved by changing the signature to F&& (again as you mentioned).
@Ashkanxy For the same reason that you cannot call a function void f(int& x) with f(1). A non-const lvalue reference (x) cannot bind to a rvalue (1). F&& is special because F is a template parameter, and therefore this is a so-called forwarding reference with special deduction rules that can bind any value category.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.