函数原型和函数实现签名是否可以使用const不一致?
我喜欢在可能的情况下将值参数声明为const
,并且通过搜索SO,我发现这并不太常见 。 像这样:
int add(const int a, const int b) { ... }
但我想知道: const
for values是我的函数的实现细节,而不是它的接口的一部分。 因此将它放入原型似乎是不必要的。
上述函数的原型似乎工作得很好:
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
?
函数类型不同是不行的,但是您需要知道函数类型的哪一部分以及函数类型的一部分。 在您的情况下,参数的const
不重要,因此函数类型是相同的,尽管声明看起来与定义不同。
在你的情况下它是
8.3.5函数[dcl.fct]
5单个名称可用于单个范围内的多个不同function; 这是函数重载(第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))&)
– >不是顶级的
我希望这清除了对函数类型的一些误解。
对于你的其他问题:我建议保持声明和定义相同,因为它可能会使人感到困惑(就像这个问题所certificate的那样;)。
对于你给出的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
应该没问题,但请注意,并非所有编译器都没有bug。 例如,Oracle Sun编译器有一个长期存在的问题 ,它以不同方式修改int f(int)
和int f(const int)
。
为了避免任何混淆的可能性,你真正打算通过const
引用,我通常建议避免公共函数声明中的顶级const
,并避免可能的编译器问题,我也会在函数定义中避免它。
(注意,在参数列表中将char **
更改为const char* const argv[]
不会添加顶级const,这是一个真正的签名更改char**
只相当于函数参数列表中的char** const
。 )
const for values是我的函数的实现细节,而不是它的接口的一部分。
这是你思考的缺陷,当谈到引用和指针const
与接口有关时,它告诉程序员使用接口,你传递的内容不会被函数改变。 它告诉编译器相同并将程序员绑定到此契约。
具有const
参数的函数和具有非const
参数的函数是不同的。
然而,通过值传递,将复制参数,在这种情况下,更改它们不是问题。 你的int
是通过值传递的,这个const
不会有太大的区别。
但是,我个人认为这不是滥用接口不一致的原因,并且使接口在一个地方与另一个地方不同。
通过ref传递,ref到const
与ref非常不同。