引入 lambda 后,函数内的类是否有任何用例?

发布于 2024-11-27 01:28:30 字数 380 浏览 2 评论 0原文

来自 wikipedia 关于 Lambda 函数和表达式的文章 :

用户通常希望在该地点附近定义谓词函数 他们在其中调用算法函数。语言只有一种 实现这一点的机制:能够在 a 内部定义一个类 功能。 ...函数中定义的类不允许在模板中使用它们

这是否意味着在 C++0x 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一人独醉 2024-12-04 01:28:30

我不确定我是否理解您的困惑,但我只是陈述所有事实并让您解决。 :)

在 C++03 中,这是合法的:

#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
}

但是如果我们尝试这样做,则不是:

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

int main()
{
    // ...

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

这给我们留下了一个问题:我们想要定义用于此函数的谓词,但我们不能把它 < em>在函数中。所以我们必须将它移动到任何外部范围并在那里使用它。这不仅使范围内出现了其他人不需要知道的内容,而且将谓词移离了它的使用位置,使得阅读代码变得更加困难。

对于函数内偶尔重用的代码块(例如,在上面的循环中;您可以使用函数谓词及其参数来判断某些复杂的事物),它仍然可能有用,但大多数情况下我们想在模板中使用它们的时候。

C++0x 更改了规则以允许上述代码工作。他们还添加了 lambdas: 语法,用于将函数对象创建为表达式,如下所示:

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

    // ...
}

这与上面完全相同,但更简单。那么“真正的”本地课程我们还有用吗?当然。毕竟,Lambda 缺乏完整的功能:

#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
}

也就是说,使用 lambda,您可能不会比以前更多地看到本地类,但出于完全不同的原因:一个几乎无用,另一个几乎被取代。

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.

两个我 2024-12-04 01:28:30

引入 lambda 后,函数内部的类是否有任何用例?

确实。在函数内部拥有一个类意味着:

  • 将其本地化为打算使用它的代码的私有实现细节,
  • 防止其他代码使用并依赖于它,
  • 独立于外部命名空间。

显然,存在一个阈值,在函数内使用大型类会损害可读性并混淆函数本身的流程 - 对于大多数开发人员和情况来说,该阈值非常低。对于一个大类,即使只有一个函数打算使用它,将它们放入单独的源文件中可能会更干净。但是,这一切都只是为了口味而调整。

您可以将其视为类中具有私有函数的逆过程:在这种情况下,外部 API 是类的公共接口,而函数保持私有。在这种情况下,函数使用类作为私有实现细节,并且后​​者也保持私有。 C++ 是一种多范式语言,在对程序组织和 API 公开的层次结构建模时适当地提供了这种灵活性。

示例:

  • 一个函数处理一些外部数据(例如文件、网络、共享内存...),并希望使用一个类来表示 I/O 期间的二进制数据布局;如果该类只有几个字段并且对其他函数没有用处,则它可能会决定将该类设为本地类 函数
  • 想要对一些项目进行分组并分配它们的数组以支持它为导出其返回值而进行的内部计算;它可能会创建一个简单的结构来包装它们。
  • 给一个类一个令人讨厌的按位枚举,或者可能想要重新解释一个浮点型或双精度型以访问尾数/指数/符号,并在内部决定使用以下方式对值进行建模为了方便起见,具有合适宽度的位域的 struct (注意:实现定义的行为)

函数中定义的类不允许在模板中使用它们

我认为您评论说其他人的答案已经解释了这一点,但无论如何......

void f()
{
    struct X { };
    std::vector<X> xs;  // NOPE, X is local
}

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
}
月亮邮递员 2024-12-04 01:28:30

在函数内部定义结构从来都不是解决谓词缺乏的特别好的方法。如果你有一个虚拟基地,它就可以工作,但它仍然是一种相当丑陋的处理方式。它可能看起来有点像这样:

struct virtual_base {
  virtual void operator()() = 0;
};

void foo() {
  struct impl : public virtual_base {
    void operator()() { /* ... */ }
  };

  register_callback(new impl);
}

当然,如果您愿意,您仍然可以继续使用这些类内部函数 - 它们没有被弃用或削弱;他们从一开始就受到限制。例如,此代码在 C++0x 之前的 C++ 版本中是非法的:

void foo() {
  struct x { /* ... */ };
  std::vector<x> y; // illegal; x is a class defined in a function
  boost::function<void()> z = x(); // illegal; x is used to instantiate a templated constructor of boost::function
}

这种用法实际上在 C++0x 中合法,因此内部类的实用性实际上得到了扩展。但大多数时候这仍然不是一个很好的做事方式。

Defining structures inside functions was never a particularly good way to deal with the lack of predicates. It works if you have a virtual base, but it's still a pretty ugly way to deal with things. It might look a bit like this:

struct virtual_base {
  virtual void operator()() = 0;
};

void foo() {
  struct impl : public virtual_base {
    void operator()() { /* ... */ }
  };

  register_callback(new impl);
}

You can still continue to use these classes-inside-functions if you want of course - they're not deprecated or crippled; they were simply restricted from the very start. For example, this code is illegal in versions of C++ prior to C++0x:

void foo() {
  struct x { /* ... */ };
  std::vector<x> y; // illegal; x is a class defined in a function
  boost::function<void()> z = x(); // illegal; x is used to instantiate a templated constructor of boost::function
}

This kind of usage was actually made legal in C++0x, so if anything the usefulness of inner classes has actually be expanded. It's still not really a nice way of doing things most of the time though.

享受孤独 2024-12-04 01:28:30

升压变体。

Lambda 不适用于变体,因为变体需要具有多个operator()(或具有模板化operator())的对象。 C++0x 现在允许在模板中使用本地类,因此 boost::apply_variant 可以使用它们。

Boost.Variant.

Lambdas don't work with variants, as variants need objects that have more than one operator() (or that have a templated operator()). C++0x allows local classes to be used in templates now, so boost::apply_variant can take them.

哎呦我呸! 2024-12-04 01:28:30

正如托尼提到的,函数内的类不仅仅与谓词有关。除了其他用例之外,它还允许创建一个工厂函数,该函数创建确认接口的对象,而无需公开实现类。看这个例子:

#include <iostream>
/* I think i found this "trick" in [Alexandrescu, Modern C++ Design] */
class MyInterface {
    public:
        virtual void doSomethingUseful() = 0;
};

MyInterface* factory() {
    class HiddenImplementation : public MyInterface {
        void doSomethingUseful () {
            std::cout << "Hello, World!" << std::endl;
        }
    };

    return new HiddenImplementation();
}


int main () {
    auto someInstance = factory();

    someInstance->doSomethingUseful();
}

As Tony mentioned, a class inside a function is not only about predicates. Besides other use cases, it allows to create a factory function that creates objects confirming to an interface without exposing the implementing class. See this example:

#include <iostream>
/* I think i found this "trick" in [Alexandrescu, Modern C++ Design] */
class MyInterface {
    public:
        virtual void doSomethingUseful() = 0;
};

MyInterface* factory() {
    class HiddenImplementation : public MyInterface {
        void doSomethingUseful () {
            std::cout << "Hello, World!" << std::endl;
        }
    };

    return new HiddenImplementation();
}


int main () {
    auto someInstance = factory();

    someInstance->doSomethingUseful();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文