函数原型和函数实现签名是否可以使用const不一致?

时间:2013-03-08 15:36:19

标签: c++ c header const function-prototypes

我想尽可能将值参数声明为const,并通过搜索SO,我发现that's not too uncommon。像这样:

int add(const int a, const int b)
{
    ...
}

但我想知道:const 是我的函数的实现细节,而不是它的界面的一部分。因此将它放入原型似乎是不必要的。

上述功能的原型似乎运行得很好:

int add(int a, int b);

但我听说过一些问题,例如:将main函数的argc声明为const可能会导致问题:

int main(const int argc, const char* const argv[])

那么这是否意味着int add(int a, int b)int add(const int a, const int b)毕竟不相同?

如果技术上没问题,我应该做些什么?我也可以在原型中省略变量名,但我没有,所以也许我不应该遗漏const

3 个答案:

答案 0 :(得分:10)

函数类型不同,但你需要知道函数类型的一部分是什么,什么不是。在您的情况下,参数的const并不重要,因此函数类型是相同的,尽管声明看起来与定义不同。

在你的情况下,它是

  

8.3.5函数[dcl.fct]

     

5 单个名称可用于单个范围内的多个不同功能;这是函数重载(第13条)。函数的所有声明都应在return类型和parameter-type-list中完全一致。使用以下规则确定函数的类型。每个参数的类型(包括函数参数包)由其自己的decl-specifier-seq和声明符确定。后   确定每个参数的类型,将“T的数组”或“返回的函数T”的任何参数分别调整为“指向T的指针”或“指向函数返回T的指针”。生成参数类型列表后,在形成函数类型时,将删除修改参数类型的任何顶级cv限定符。生成的已转换参数类型列表以及省略号或函数参数包的存在与否是函数的parameter-type-list。 [注意:这种转变没有   影响参数的类型。例如,int(*)(const int p, decltype(p)*)int(*)(int, const int*)是相同的类型。 - 结束说明]

看起来,它需要一些解释,所以我们开始:我们的例子中的重要句子是:在生成参数类型列表之后,修改参数类型的任何顶级cv限定符都会被删除形成功能类型。

这意味着将删除所有顶级 cv-qualifier。为了解释顶级意味着什么,我将以非法方式编写类型以强调const所指的内容:

  • const int = (const (int)) - >这是顶级const
  • const int* = ((const (int))*) - >不是顶级,而是在第二级
  • const int* const = (((const (int))*) const) - >第二个const位于顶级
  • const int& = ((const (int))&) - >不是顶级的

我希望这清除了对函数类型的一些误解。

对于你的其他问题:我建议保持声明和定义相同,因为它可能会使人感到困惑(就像这个问题所证明的那样)。

您提供的main示例:

int main( const int argc, const char* const argv[] )

是,根据标准的上述引用,相当于:

int main( int argc, const char* const* argv )

因此const添加的argv不会最终作为顶级const被移除,因此它是main的格式错误的函数类型,期待:

int main( int argc, char** argv )

关于遗漏参数名称的最后一个问题:我不会这样做,因为对我来说,它们是函数的文档的一部分。它们传达函数的意图和语义(如果你明智地选择它们)。

答案 1 :(得分:1)

在声明和函数定义之间为函数参数设置不同的顶级const应该没问题,但请注意并非所有编译器都没有错误。例如,Oracle Sun编译器有long standing issue,其中int f(int)int f(const int)不同。

为了避免任何混淆的可能性,你真的打算通过const引用我通常建议在公共函数声明中避免顶级const并避免可能的编译器问题我会在函数定义中避免它同样。

(请注意,在参数列表中将char **更改为const char* const argv[]不会添加顶级常量,这是真正的签名更改。char**只会等同于char** const在函数参数列表中。)

答案 2 :(得分:0)

  

const for values是我的函数的实现细节,而不是它的接口的一部分。

这是你思考的缺陷,当谈论引用和指针const与接口有关时,它告诉程序员使用接口,你传递的内容不会被函数改变。它告诉编译器相同并将程序员绑定到此契约。

具有const参数的函数和具有非const参数的函数是不同的。

然而,

按值传递,会复制参数,在这种情况下,更改它们不是问题。您的int是按值传递的,其中const不会有太大的不同。

但是,我个人认为这不是滥用接口不一致的原因,并且使接口在一个地方与另一个地方不同。

通过引用,const的引用与引用非const的引用完全不同。