C++中定义短函数名别名的最安全方法是什么?

8
假设我有一个名为 Utility 的类,在 utility.h 文件中:
class Utility {
public:
    static double longDescriptiveName(double x) { return x + 42; }
};

然后我发现我经常使用函数longDescriptiveName(...)。像一个喝了太多咖啡的不负责任的C++程序员一样,我创建了一个新文件utilitymacros.h并添加了以下内容:

#define ldn Utility::longDescriptiveName

现在我在任何使用ldn(...)*.cpp文件中包含"utilitymacros.h",这让我非常高兴,因为只需要输入三个字母而不是28个字母。

问题:有没有比使用#define更安全(更合适)的方法?

我注意到,我必须在包含boost头文件之后包含"utilitymacros.h",这显然不是很好,因为这是冲突的一个迹象(尽管我收到的Boost错误并没有明确指出冲突的原因)。

澄清1:关于代码可读性

如果你认为这会对代码可读性产生负面影响,我向你保证它不会,因为这是一组被广泛使用的小型函数。一个众所周知的例子是stoi代表stringToInteger。另一个例子是pdf代表probabilityDensityFunction等。因此,在我看来,如果我想要执行以下操作,stoi更易读:

int x = stoi(a) + stoi(b) + stoi(c) + stoi(d);

那么:

int x = Utility::stringToInteger(a) + Utility::stringToInteger(b)
        + Utility::stringToInteger(c) + Utility::stringToInteger(d);

或者:

int x = Utility::stringToInteger(a);
x += Utility::stringToInteger(b);
x += Utility::stringToInteger(c);
x += Utility::stringToInteger(d);

澄清2: 编辑器宏

我选择使用Emacs作为我的IDE,并且使用Kinesis键盘。因此,我经常使用许多键盘宏、自定义键盘快捷方式,以及实际修改编辑器中所见的内容与实际存储在h/cpp文件中的内容不同。但是,我仍然觉得在少数情况下使用函数缩写的简单性和视觉可读性(如上所述)确实是我正在寻找的结果(当然这在一定程度上是主观的)。


3
我认为这不是个好主意,因为它会影响代码的可读性。 - πάντα ῥεῖ
1
我会认为pdf是一种文件格式,然后会非常困惑。字符是自由的,不使用它们并不能节约环境。 - Bo Persson
也许对你来说,短名称很容易读懂,但对其他人来说却很困难,尤其是当它们被广泛地使用时。在我的旧工作中,有很多三字符函数名,这是我离开那里的许多原因之一:代码变得难以阅读。当然,不仅仅因为函数和变量名称,但这是其中的一部分。 - Skalli
6个回答

15

你可以编写inline函数来代替宏,并将调用转发给实际函数:

inline double ldn(double x)
{
   return Utility::longDescriptiveName(x);
}

这肯定比宏 更安全


2
+1 绝对内联函数更安全,因为有类型检查,我认为推荐使用(C++风格)而不是 #define(C风格和不太安全)。另外注意:与宏不同,内联缺乏使用任何数据类型的功能,这可以通过在内联中使用模板来实现! - Abdurahman
@Nawaz,我假设内联函数不是Utility类的一部分,对吗?如果是这样,您建议将内联定义放在与utility.h相同的头文件中,还是创建一个名为utilityhelpers.h的单独头文件呢? - Alan Turing
@LexFridman:是的。它在Utility类之外。你可以把它放在同一个头文件中,但在类之外。这取决于你。 - Nawaz

7
您可以使用函数引用:
```

您可以使用函数引用:

```
double (&ldn)(double) = Utility::longDescriptiveName;

难道不应该是 static double (&ldn)(double) = ... 吗? - Nawaz
3
在C++11中,auto &&ldn = Utility::longDescriptiveName;非常惯用。在任何情况下使用static有什么优势? - Potatoswatter
1
@Potatoswatter:这是一个头文件;使用static可以避免多重定义错误。 - Nawaz
static 用于定义具有相同名称的多个不同对象。使用 extern 可能会更好。无名命名空间通常是首选。 - Potatoswatter
2
使用函数引用可能会影响函数调用的内联能力。 - jogojapan
显示剩余2条评论

3

你可以在文本编辑器中配置片段/宏或类似的东西,这样你只需要输入ldn或类似的内容,代码就不必通过预处理器运行,从而避免难以找到的错误。


2
此外,一旦打出来,它将是易于理解的。 - user395760

2

我不知道这是否有所帮助,但我认为问题的一部分可能是使用了过于通用的命名空间(或类名),比如Utility

如果我们使用stringToInteger代替Utility::stringToInteger,那么:

namespace utility {
  namespace type_conversion {
    namespace string {
      int to_int(const std::string &s);
    }
  }
}

然后,该函数可以在本地使用,例如:
void local_function()
{
  using namespace utility::type_conversion::string;

  int sum = to_int(a) + to_int(b) + to_int(c) + to_int(d);
}

类似地,如果使用了类/结构和静态函数(这可能是有好处的),我们会有如下代码:
strut utility {
  struct type_conversion {
    struct string {
      static int to_int(const std::string &s);
    };
  };
};

本地函数的代码可能类似于以下内容:

void local_function()
{
  typedef utility::type_conversion::string str;

  int sum = str::to_int(a) + str::to_int(b)
              + str::to_int(c) + str::to_int(d);
}

我意识到我并没有告诉你任何关于语法的东西,这更像是提醒大家一个事实:命名空间和类的组织结构本身在使代码更易读(和编写)方面起着重要作用。


2
一种替代方案是将您的函数重命名并将其放在名称空间中,而不是类中,因为它无论如何都是静态的。 utility.h变成了:
namespace Utility {
    // long descriptive comment
    inline double ldn(double x) { return x + 42; }
}

然后你可以在客户端代码中加入using namespace Utility;

我知道有很多风格指南认为短名称是不好的,但我不明白遵守某些风格然后规避它的意义所在。


-1

你可以使用别名模板(自C++11起)。

  using shortName = my::complicate::function::name;

可以只使用类名,但不能使用函数名。 - daohu527

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接