C++:隐藏一些函数
Posted
技术标签:
【中文标题】C++:隐藏一些函数【英文标题】:C++: hiding some functions 【发布时间】:2011-05-23 22:04:32 【问题描述】:我重新定义了一些数学函数(以便它们更快 - 即:不太准确 - 或使用模板)。我将这些函数放在一个命名空间中,它们工作得很好。
不过,我经常忘记从我的命名空间调用函数(即:当我想调用 cos
时,我忘记写 mymath::cos
或 using mymath::cos;
),而且很难找出在哪里调用我忘记了(直到现在我只是通过分析才发现它)。
考虑到
我仅在我的数学标头中包含标准math.h
或 cmath
标头,并且
我需要包含标准数学标头(因为我的一些函数只是标准函数的包装器,我希望它们是内联的或者是模板化的),
如果使用全局命名空间(即:没有命名空间)数学函数,是否有一种可移植的方式隐藏标准数学函数,以便报告编译错误?
一个解决方案可能是在我的数学头文件的底部放置一个using namespace mymath;
,但这个解决方案似乎并不那么好:它破坏了命名空间的整个目的;我宁愿明确说明是使用来自mymath
还是来自std
的函数,这样我就不得不在溃烂或更准确的函数之间做出选择,而不会忘记它。
编辑:
许多答案说如果我使用全局命名空间中的cos
(不使用std
或mymath
),并包含cmath
(而不是math.h
),编译应该会失败。
我不知道标准对此有何规定,但是:
#include <cmath>
int main( )
cos( M_PI );
return 0;
使用 GNU GCC (g++
) 4.5.1(和旧版本)编译良好。
【问题讨论】:
关于编辑你是正确的:“未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明注入命名空间 std”。 【参考方案1】:把它放在一个头文件中,并#include 它无处不在:
namespace DontUseMe
double cos (double) ;
// ...etc.
using namespace DontUseMe ;
【讨论】:
呃,这看起来不错!使用 Boost.StaticAssert 每当我使用全局命名空间数学函数时,它都会给我编译时错误... 当你这样做并且在某些编译单元中包含cmath
时,编译器会告诉你double cos(double)
是模棱两可的。因此命名空间 wrestling ;)
@Fritschy:这就是重点!它强制使用显式命名空间限定符。这正是 OP 想要的。
好吧,TonyK,:) 没想过故意破坏程序 :)。【参考方案2】:
如果您只包含 cmath
而不是 math.h
,则该标头中的所有函数都应位于 std:: 命名空间中。永远不要使用using namespace std;
,你会没事的。 (cmath
只是 math.h
与命名空间中的所有东西)
【讨论】:
不,不是来自 GNU GCC 4.5.1 的cmath
。我的意思是,是的,它在 std
命名空间中提供数学函数,但它也在全局命名空间中提供数学函数(即:::cos
,没有任何命名空间),这是我想要避免的.【参考方案3】:
您是否需要在头文件中直接包含 math.h 和 cmath 头文件?如果确实需要,请尝试包含这样的标题:
namespace arbitrary_name
#include <math.h>
这将包含一个新命名空间中的所有 math.h 定义,因此您不会在其他地方意外使用它们。
这不是理想的解决方案。也许有更好的方法可以使用匿名命名空间来做到这一点,但我并不清楚解决方案。
【讨论】:
这会起作用,但前提是math.h
仅包含 C 代码。我更喜欢包含cmath
,以便它声明许多具有相同名称的标准函数的重载函数(即:double cos(double x);
、float cos(float x);
...)。 -- 无论如何,我认为这是我能做的最好的......
The River,这不起作用,因为该库导出的所有符号都不在您放入标头的命名空间中。【参考方案4】:
不幸的是,最可靠的解决方案是不使用与标准库相同的函数名。幸运的是,标准函数名称很简洁,并且被大量缩写,因此诸如 cosine()
、sine()
、exponent()
、arctan()
之类的名称将是独一无二的(并且可以说更好),而不必用笨拙的前缀来装饰名称。
或者,您可以保留相同的名称但将它们大写:Sin()
、Cos()
、Exp()
等。
【讨论】:
它当然可以,但是由于我忘记显式使用给定的命名空间,我相信我经常会忘记将自定义名称用于标准函数。但是,找到我使用标准函数名称的位置会更容易...... 我宁愿选择全名也不愿大写。 @Matthieu:我完全同意,这很可怕,但可能会吸引一些人。【参考方案5】:这个思路怎么样:在包含
#define sin blahblahblah (just to generate an error)
#define cos blahblahblah (just to generate an error)
发生的情况是,每一个罪都会被 blahblahblah 代替,这将导致错误。但是会发生的情况是 mymath::sin 将被 mymath::blahblahblah 替换(因为 #define 是字面意思),所以它也会产生错误。在这种情况下,如果您想让任务更轻松,您只需在 mymath 中临时定义函数 blahblahblah 以避免显示 mymath::sin 错误,然后编译并修复所有这些错误。
但是,我建议只制作“在文件中查找”并完成所有功能,我相信对于一个非常大型的项目来说,它不会超过一个小时。
希望对您有所帮助。
问候, 拉菲德
【讨论】:
这是一个可能的解决方案。标准库中的标准数学函数通常是宏。 嗯,希望能在编译时找到一种方法,无需两个编译步骤(一个检查函数有效性,另一个实际编译)......无论如何是的,这个会工作的。 这行不通,您必须将它们定义为函数样式的宏,并且您必须检查和undef
它们,因为它们被允许在 @ 中成为宏(以及函数) 987654323@。如果您使用非函数样式的宏,那么任何使用 (std::sin)(x)
或 (mymath::sin)(y)
的尝试仍会被这些宏破坏。
这是不允许的:“包含标准库头文件的翻译单元不得在任何标准库头文件中声明#define 或#undef 名称”
@Charles,是的,它们是非函数宏样式,仅用于对函数名称进行重新映射。我已经在回答中解释了这一点,这就是为什么我建议他在 mymath 命名空间中定义函数 blahblahblah。【参考方案6】:
在单独的文件中编写一些包装函数。
#include <math.h>
namespace my_wrapper
float sin(float n)
return std::sin(float n);
;
或者类似的东西。然后只在您的其他文件中使用它们,甚至不包含或在其他源文件中。是的,为它们都编写转发函数有点痛苦,但这只是一项临时工作,而且没有那么多......
使用现代编译器可以链接时间代码生成并且可以跨目标文件内联,这应该不会是低效的......
【讨论】:
模板怎么样?template< typename T1, typename T2 > PROMOTE(T1,T2) pow( T1 x, T2 y ) return std::pow( (PROMOTE(T1,T2)) x, (PROMOTE(T1,T2)) y );
? (PROMOTE
是我定义的一个宏,它使用模板来提升类型 - 即:PROMOTE(int,double) 是 double)。【参考方案7】:
到目前为止,Clifford 是我最喜欢的答案,但您可能会想到另一种选择:修改此项目的标准标题(仅)。
您选择的编译器应该有一个选项来指示标准库所在的位置,因此您可以在项目中复制 STL,并修改文件,以便不再将有问题的名称注入全局命名空间。
这是 hackish,但这是我能想到的唯一方法,没有使用脚本检查代码中是否出现任何不合格的 cos
/ sin
(即紧接在 ::
之前)。
【讨论】:
以上是关于C++:隐藏一些函数的主要内容,如果未能解决你的问题,请参考以下文章