0

方案一:

#include <iostream>

std::string Hello(void){return "Hello";}
std::string World(void){return "world!";}

int main(){

    std::cout << Hello() << " " << World() << std::endl;
}

函数 Hello() 和 World() 存在于全局命名空间中。
这意味着它们可以被声明之后的任何其他函数调用(或者在这种情况下,我提供了定义并且不需要先声明)。

我有一个问题,因为随着我的项目变得越来越大,我包含了更多的头文件,这些头文件用很多函数填充了全局命名空间,并且我冒着函数签名冲突的风险,或者更糟糕的是,不小心调用了应该只调用的错误函数作为另一个功能的子任务。

我试图遵循将任务功能分解为子任务的范式,因此在另一个特定函数的范围之外调用特定函数是没有意义的。

这是一种解决方法,除了由于缩进深度导致代码变得不可读之外,我想知道是否存在任何性能或实现问题。lambda 函数目前对我来说有点神奇,所以我对不可预见的危险感到好奇。

方案二:

#include <iostream>

int main(){

    auto Hello = [](void) -> std::string{return "Hello";};
    auto World = [](void) -> std::string{return "world!";};

    std::cout << Hello() << " " << World() << std::endl;
}

Hello() 和 World() 被封装在 main() 内部,不能从 main() 的作用域之外调用。
这就是不一样的一切吗?

4

3 回答 3

1

C++ 中实现您想要的首选机制是使事物(函数、类型、对象)私有(不是在可访问性的意义上,不像关键字),这样它们就不能在另一个模块中命名。这完全防止了碰撞。

例如,考虑一个包含头文件的模块:

// List dependencies
#include <string>

// It's customary to put things in a namespace
// Note that namespaces are commonly cross-module

namespace ns {

// Declarations visible to all
std::string hello_world();

} // ns

和这样的实现:

// include header listed above
#include <header.hpp>

// This contains declarations visible to this module only
namespace {

std::string hello_part();

// This is both a declaration and a definition
std::string world_part()
{ return "world!"; }

} // namespace

// Definition of function declared in header
std::string ns::hello_world()
{
    // Implemention defers to private parts that are visible here
    return hello_part() + " " + world_part();
}

// Definition of private function
// We need to reopen the unnamed namespace for that

namespace {

std::string hello_part()
{ return "Hello"; }

} // namespace

现在另一个模块可以hello_part自己声明另一个模块,不需要是一个声明相同的函数,甚至根本不是一个函数,也不会有冲突。将有两个不同且独立的实体——就像一个for语句可以有自己的int i;变量而没有任何其他的干扰i

hello_part至于您问题的另一部分,是否将world_part上述内容实现为普通的旧函数或函数对象(通过 lambda 表达式或其他方式)并不重要。但是请记住,由于它们不会关闭任何东西,因此它们并没有太大的封闭性。C++ lambda 表达式确实允许关闭任何东西,包括局部变量(也称为局部捕获),但类型系统的表达能力不够强,无法在某些情况下解决向上的 funarg 问题而不会付出小代价。但是,忠于 C++ 信条,这不能在你背后发生,你需要通过例如std::function. 对于这些情况,我会反对 lambda 表达式,因为我认为有更好的选择(我不会在这里展开)。

但总的来说,决定是否要使用 lambda 表达式是一个不会(也不应该)影响程序模块化的考虑因素。

一个更长更详细的答案将解释范围和可见性、声明和实现、命名空间、模块和可访问性的不同角色,这些都可以用来使程序模块化。最好不要将它们混为一谈。我的示例使用除了可访问性之外的所有这些东西来满足其需求,但这远非唯一的方法。

于 2012-12-20T00:44:56.653 回答
0

首先,它被称为“命名空间”。其次,这种 lambda 并没有真正的缺点。事实上,它们有好处,因为您现在可以在其中使用局部变量,这允许重用更多逻辑。

于 2012-12-20T00:04:31.920 回答
0

我不会这样做。在您的情况下,您最终将创建巨大的函数以允许在内部定义 lambda,并且您最终将获得主体内容更难维护的函数。

在 C++11 和 lambdas 之前已经有非常大的项目,并且通过不同的方式管理冲突的风险,包括像 DeadMG 已经提到的命名空间,还有类和面向对象的设计以及其他形式的封装(将本地函数定义为static在实现文件的命名空间级别,强制内部链接并避免与其他翻译单元冲突。在此之上,如果您为标识符仔细选择有意义的名称,您应该避免 99% 的冲突。

如果您真的要从事大型项目,请考虑阅读 John 的 Lakos大型 C++ 软件设计

于 2012-12-20T00:27:37.313 回答