C++ 函数原型和函数实现签名不一致地使用const可以吗?

C++ 函数原型和函数实现签名不一致地使用const可以吗?,c++,c,header,constants,function-prototypes,C++,C,Header,Constants,Function Prototypes,我喜欢尽可能将偶数值参数声明为const,通过搜索,我发现了这一点。像这样: int add(const int a, const int b) { ... } 但是我想知道:constforvalues是我函数的一个实现细节,而不是它接口的一部分。因此,将其放入原型中似乎没有必要 上述功能的原型似乎工作正常: int add(int a, int b); 但我听说过一些问题,例如将主函数的argc声明为const可能会导致问题: int main(const int argc, c

我喜欢尽可能将偶数值参数声明为
const
,通过搜索,我发现了这一点。像这样:

int add(const int a, const int b)
{
    ...
}
但是我想知道:
const
forvalues是我函数的一个实现细节,而不是它接口的一部分。因此,将其放入原型中似乎没有必要

上述功能的原型似乎工作正常:

int add(int a, int b);
但我听说过一些问题,例如将主函数的argc声明为const可能会导致问题:

int main(const int argc, const char* const argv[])
那么这是否意味着
intadd(inta,intb)
intadd(constinta,constintb)
毕竟是不同的呢

如果技术上可以的话,我应该这样做吗?我也可以在原型中省略变量名,但我不这样做,所以也许我也不应该省略
const

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

你的情况是

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

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

这意味着删除所有顶级cv限定符。为了解释top-level的含义,我将以非法的方式编写类型,以强调
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 )
因此,为
argv
添加的
const
不会最终作为顶级
const
被删除,因此它是
main
的格式不正确的函数类型,它期望:

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

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

这就是你思维中的缺陷,当谈到引用和指针时,const与接口有关,它告诉使用接口的程序员你传递的内容不会被函数改变。它告诉编译器同样的道理,并使程序员受此契约约束

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

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

然而,我个人并不认为这是滥用不一致接口的理由,并使接口在不同的地方不同


虽然通过ref传递,但对
const
的ref与对非
const
的ref有很大不同,在函数的声明和定义之间对函数参数使用不同的顶级
const
应该是可以的,但请注意,并非所有编译器都没有bug。例如,OracleSun编译器有一个函数,它以不同的方式处理
intf(int)
intf(const int)

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

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