有没有办法通过引用传递,并在函数调用中显式传递值?

Tre*_*key 23 c c++ parameters parameter-passing c++11

如果你要查看这段代码,

int x = 0;
function(x);
std::cout << x << '\n';
Run Code Online (Sandbox Code Playgroud)

您将无法通过任何语法方式验证参数x是通过引用传递还是通过值传递.您可以肯定的唯一方法是查看函数声明或函数定义.

这是一个简单的例子,我认为这可能是一个问题:

std::string Lowercase(std::string str); //<- this is hidden away in code; probably in a different file.

int main(){
    std::string str = "HELLO";
    Lowercase(str);
    std::cout << str << '\n'; //<- Bug! we expected to output "hello".  The problem is not very easy to spot, especially when a function name sounds as though it will change the passed in value.
}
Run Code Online (Sandbox Code Playgroud)

为了避免必须在函数调用和函数声明(或在某些情况下,文档)之间跳转以理解函数行为,有没有办法在函数调用的语法中显式地记录参数是期望改变(即参考参数)或发送副本(即通过值传递)?

我意识到还有一个选择传递const&,它具有类似于传递值的概念,因为传入的变量在函数调用之后不会更改其值.


我确信语言中有各种各样的情况可能会增加理解参数传递的复杂性 - 但我很好奇,有没有办法以我想要的方式解决这个问题?

我注意到有些人写了两个类似的功能.其中一个采用值参数,另一个采用指针.这允许调用这样的函数:

Lowercase(str); //we assume the value will not change
Lowercase(&str); //we assume the value will change
Run Code Online (Sandbox Code Playgroud)

但是这个解决方案还有很多其他问题,我不想失去参考的好处.另外,我们仍在对行为做出假设.

Die*_*ühl 24

有些人坚持认为传递可变对象的正确方法是使用指针.也就是说,你会通过

Lowercase(&str);
Run Code Online (Sandbox Code Playgroud)

...... Lowercase()显然,实现了一个指针.这种方法可能适合您的需求.

但是,我想提一下,这不是我要做的!相反,我赞成的方法是使用适当的名称.例如,

inplace_lowercase(str);
Run Code Online (Sandbox Code Playgroud)

几乎说了它将要做什么.显然,inplace_lowercase()实际上是一个算法,并且可以合理地称之为具有一点魔力

inplace_lowercase(str.begin() + 1, str.end());
Run Code Online (Sandbox Code Playgroud)

同样.

以下是我不喜欢通过指针传递参数和/或为什么我不相信参数如何传递的明确指示的几个原因:

  • 指针可以为空.在我看来,强制参考参数应该是一个参考.
  • 通过指针传递仍然不表示参数是否可以被修改不是因为参数可能是a T const*.
  • 拥有有意义的名称使得实际上更容易理解首先发生的事情.
  • 在没有查阅其文档的情况下调用某些内容和/或知道被调用的函数将执行什么操作无论如何都无法正常工作并指示事情如何通过以试图解决更深层次问题的症状.

  • +1如果对象可能不存在则接受指针; 如果对象必须存在,则接受引用,并且您计划更改它; 如果对象必须存在并且您不打算更改它,则接受const引用; 如果参数是一个值而不是一个对象,则接受一个值(公认有些含糊不清).[我知道这不会解决原始问题因此是评论,而不是答案.] (2认同)

Dan*_*rey 9

我不确定我完全理解你的要求,但也许这是你可以使用的东西:

template<typename T>
void foo( T ) { static_assert( sizeof(T)==0, "foo() requires a std::ref" ); }

void foo( std::reference_wrapper<int> t )
{
    // modify i here via t.get() or other means of std::reference_wrapper
}

int main()
{
    int i = 42;
    // foo( i ); // does not compile, static_assert fires
    foo( std::ref( i ) ); // explicit std::ref visible on the caller's side
}
Run Code Online (Sandbox Code Playgroud)

  • [实例](http://coliru.stacked-crooked.com/a/7647714d80a38d80)的替代方案. (2认同)