草庐IT

c++ - 顶级 const 不影响函数签名

coder 2023-11-14 原文

在 C++ Primer 第五版中,它说:

int f(int){ /* can write to parameter */}
int f(const int){ /* cannot write to parameter */}

这两个函数无法区分。但是如您所知,这两个函数在更新参数的方式上确实存在差异。

谁能给我解释一下?


编辑
我想我没有很好地解释我的问题。我真正关心的是为什么 C++ 不允许这两个函数同时作为不同的函数,因为它们在“是否可以写入参数”方面确实不同。直觉上应该是!


编辑
按值传递的本质其实是通过将参数值复制到参数值来传递。即使对于引用指针,您复制的值是地址。从调用者的角度来看,无论是 const 还是 non-const 传递给函数都不会影响复制到参数的值(当然还有类型)。
top-level constlow-level const 之间的区别在复制对象时很重要。更具体地说,复制对象时忽略顶级常量(不是低级常量),因为复制不会影响复制的对象。复制到或复制自的对象是否为 const 并不重要。
所以对于调用者来说,区分它们是没有必要的。从函数的角度来看,顶级 const 参数可能不会影响函数的接口(interface)和/或功能。这两个函数实际上完成的是同一件事。为什么要费心实现两个拷贝?

最佳答案

allow these two functions simultaneously as different function since they are really different as to "whether parameter can be written or not". Intuitively, it should be!

函数的重载是基于调用者提供的参数。在这里,调用者确实可以提供 const 或非 const 值,但从逻辑上讲,它对被调用函数提供的功能应该没有影响。考虑:

f(3);
int x = 1 + 2;
f(x);

如果 f() 在每一种情况下做不同的事情,那将是非常困惑的!这段调用 f() 的代码的程序员可以对相同的行为有合理的期望,可以自由地添加或删除传递参数的变量,而不会使程序无效。这种安全、理智的行为是您想要证明异常(exception)的出发点,而且确实有一个 - 当函数重载时,行为可以改变 ala:

void f(const int&) { ... }
void f(int&) { ... }

所以,我猜这就是您发现的不直观之处:C++ 为非引用提供了比引用更多的“安全性”(通过仅支持单一实现来强制执行一致的行为)。。 p>

我能想到的原因是:

  • 因此,当程序员知道非const& 参数的生命周期更长时,他们可以选择最佳实现。例如,在下面的代码中,返回对 F 中的 T 成员的引用可能会更快,但是如果 F 是一个临时的 (如果编译器匹配 const F&) 则可能需要按值返回。这仍然非常危险,因为调用者必须知道返回的引用仅在参数存在时才有效。
    T f(const F&);
    T& f(F&);    // return type could be by const& if more appropriate
  • propagation of qualifiers like const-ness through function calls as in:
    const T& f(const F&);
    T& f(F&);

Here, some (presumably F member-) variable of type T is being exposed as const or non-const based on the const-ness of the parameter when f() is called. This type of interface might be chosen when wishing to extend a class with non-member functions (to keep the class minimalist, or when writing templates/algos usable on many classes), but the idea is similar to const member functions like vector::operator[](), where you want v[0] = 3 allowed on a non-const vector but not a const one.

When values are accepted by value they go out of scope as the function returns, so there's no valid scenario involving returning a reference to part of the parameter and wanting to propagate its qualifiers.

Hacking the behaviour you want

Given the rules for references, you can use them to get the kind of behaviour you want - you just need to be careful not to modify the by-non-const-reference parameter accidentally, so might want to adopt a practice like the following for the non-const parameters:

T f(F& x_ref)
{
    F x = x_ref;  // or const F is you won't modify it
    ...use x for safety...
}

重新编译影响

除了为什么语言禁止基于按值参数的 const 特性的重载之外,还有一个问题是为什么它不坚持 的一致性声明和定义中的 const-ness。

对于 f(const int)/f(int)... 如果您在头文件中声明一个函数,那么最好不要包含 const 限定符,即使稍后在实现文件中定义也会有它。这是因为在维护期间,程序员可能希望删除限定符......从 header 中删除它可能会触发客户端代码的无意义重新编译,因此最好不要坚持让它们保持同步 - 事实上这就是编译器不这样做的原因如果它们不同,则不会产生错误。如果您只是在函数定义中添加或删除 const,那么它接近代码读者在分析函数行为时可能关心常量的实现。如果您在头文件和实现文件中都包含 const,那么程序员希望将其设为非 const 并忘记或决定不更新头文件以避免客户端重新编译,那么它比其他方式更危险,因为程序员在尝试分析导致对函数行为的错误推理的当前实现代码时,可能会考虑 header 中的 const 版本。这都是一个非常微妙的维护问题 - 只与商业编程真正相关 - 但这是不在界面中使用 const 指南的基础。此外,从接口(interface)中省略它更简洁,这对于阅读您的 API 的客户端程序员来说更好。

关于c++ - 顶级 const 不影响函数签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17208570/

有关c++ - 顶级 const 不影响函数签名的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  3. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  4. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  5. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

  6. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  7. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  8. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  9. ruby-on-rails - 将字符串转换为 ruby​​-on-rails 中的函数 - 2

    我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。

  10. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

随机推荐