Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any use case for class inside function after introduction of lambda?

From the wikipedia article about Lambda functions and expressions:

users will often wish to define predicate functions near the place where they make the algorithm function call. The language has only one mechanism for this: the ability to define a class inside of a function. ... classes defined in functions do not permit them to be used in templates

Does this mean that use of nested structure inside function is silently deprecated after C++0x lambda are in place ?

Additionally, what is the meaning of last line in above paragraph ? I know that nested classes cannot be template; but that line doesn't mean that.

like image 269
iammilind Avatar asked Jul 29 '11 04:07

iammilind


2 Answers

I'm not sure I understand your confusion, but I'll just state all the facts and let you sort it out. :)

In C++03, this was legal:

#include <iostream>

int main()
{
    struct func
    {
        void operator()(int x) const
        {
            std::cout << x << std::endl;
        }
    };

    func f; // okay
    f(-1); // okay

    for (std::size_t i = 0; i < 10; ++i)
        f(i) ; // okay
}

But if we tried doing this, it wasn't:

template <typename Func>
void exec(Func f)
{
    f(1337);
}

int main()
{
    // ...

    exec(func); // not okay, local classes not usable as template argument
}

That left us with an issue: we want to define predicates to use for this function, but we can't put it in the function. So we had to move it to whatever outer scope there was and use it there. Not only did that clutters that scope with stuff nobody else needed to know about, but it moved the predicate away from where it's used, making it tougher to read the code.

It could still be useful, for the occasional reused chunk of code within the function (for example, in the loop above; you could have the function predicate to some complex thing with its argument), but most of the time we wanted to use them in templates.

C++0x changes the rules to allow the above code to work. They additionally added lambdas: syntax for creating function objects as expressions, like so:

int main()
{
    // same function as above, more succinct
    auto func = [](int x){ std::cout << x << std::endl; };

    // ...
}

This is exactly like above, but simpler. So do we still have any use for "real" local classes? Sure. Lambda's fall short of full functionality, after all:

#include <iostream>

template <typename Func>
void exec(Func func)
{
    func(1337);
}

int main()
{
    struct func
    {
        // note: not possible in C++0x lambdas
        void operator()(const char* str) const
        {
            std::cout << str << std::endl;
        }

        void operator()(int val) const
        {
            std::cout << val << std::endl;
        }
    };

    func f; // okay
    f("a string, ints next"); // okay

    for (std::size_t i = 0; i < 10; ++i)
        f(i) ; // okay

    exec(f); // okay
}

That said, with lambda's you probably won't see local classes any more than before, but for completely different reasons: one is nearly useless, the other is nearly superseded.

like image 186
GManNickG Avatar answered Oct 18 '22 22:10

GManNickG


Is there any use case for class inside function after introduction of lambda ?

Definitely. Having a class inside a function is about:

  • localising it as a private implementation detail of the code intending to use it,
  • preventing other code using and becoming dependent on it,
  • being independent of the outer namespace.

Obviously there's a threshold where having a large class inside a function harms readability and obfuscates the flow of the function itself - for most developers and situations, that threshold is very low. With a large class, even though only one function is intended to use it, it may be cleaner to put both into a separate source file. But, it's all just tuning to taste.

You can think of this as the inverse of having private functions in a class: in that situation, the outer API is the class's public interface, with the function kept private. In this situation, the function is using a class as a private implementation detail, and the latter is also kept private. C++ is a multi-paradigm language, and appropriately gives such flexibility in modelling the hierarchy of program organisation and API exposure.

Examples:

  • a function deals with some external data (think file, network, shared memory...) and wishes to use a class to represent the binary data layout during I/O; it may decide to make that class local if it only has a few fields and is of no use to other functions
  • a function wants to group a few items and allocate an array of them in support of the internal calculations it does to derive its return value; it may create a simple struct to wrap them up.
  • a class is given a nasty bitwise enum, or perhaps wants to reinterpret a float or double for access to the mantisa/exponent/sign, and decides internally to model the value using a struct with suitable-width bitfields for convenience (note: implementation defined behaviours)

classes defined in functions do not permit them to be used in templates

I think you commented that someone else's answer had explained this, but anyway...

void f()
{
    struct X { };
    std::vector<X> xs;  // NOPE, X is local
}
like image 3
Tony Delroy Avatar answered Oct 18 '22 20:10

Tony Delroy