9

我喜欢尽可能声明偶数值参数const,通过搜索 SO,我发现这并不少见。像这样:

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

4

3 回答 3

10

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

在你的情况下

8.3.5 函数[dcl.fct]

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

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

这意味着所有顶级cv 限定符都被删除。为了解释顶级的含义,我将以非法的方式编写类型来强调 aconst所指的内容:

  • 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的 forargv最终不会作为顶层const被删除,因此它是一个格式错误的函数类型 for main,它期望:

int main( int argc, char** argv )

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

于 2013-03-08T15:39:10.040 回答
1

const在函数的声明和定义之间为函数参数设置不同的顶层应该是可以的,但请注意,并非所有编译器都没有错误。例如,Oracle Sun 编译器有一个长期存在的问题,即它的错误int f(int)int f(const int)不同之处。

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

(请注意,在参数列表中更改char **const char* const argv[]不是添加顶级常量,而是真正的签名更改。char**仅相当于char** const在函数参数列表中。)

于 2013-03-08T17:00:57.987 回答
0

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

这就是你的想法的缺陷,当谈论引用和指针 const与接口有关的一切时,它告诉使用接口的程序员你传递的内容不会被函数改变。它告诉编译器同样的事情,并将程序员绑定到这个合约。

带参数的函数和不带const参数的const函数是不同的。

但是,按值传递将复制参数,在这种情况下更改它们不是问题。int的 s 是按值传递的,这const不会有太大的区别。

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

虽然通过 ref 传递,但 ref toconst与 ref to non- 完全不同const

于 2013-03-08T15:39:17.850 回答