【问题标题】:Why does C++ not differentiate between pass by reference and pass by value in syntax? [closed]为什么 C++ 在语法中不区分按引用传递和按值传递? [关闭]
【发布时间】:2020-01-15 03:49:47
【问题描述】:

考虑一下我有这个功能:

foo(int &x1, int x2);

有人这样称呼它:

int main(){
    int x = 1;
    foo(x, x);
}

当你只看主函数时,你看不到第一个值是通过引用传递的,第二个是通过值传递的。为什么没有一些额外的语法来“避免这个问题”?示例:

int main(){
    int x = 1;
    foo(*x, x);
}

我真的不知道,为什么 C++ 语法是这样指定的。我可以想象这背后有一个原因,我无法理解,因为我之前没有看到一个好的用例。

编辑: 可能的重复问题是处理传递引用和传递指针。我的问题是,为什么传递引用和传递值确实具有相同的被调用者语法

【问题讨论】:

  • foo(*x, x); 将是一个重大变化。有趣的是,我认为foo(x&, x); 不会。至于手头的问题,我认为现在为时已晚 - 是的,我同意在调用站点知道是否可以修改参数会很好。
  • @RoQuOTriX,只是和你打了个交道,对那次投反对票不满意,我有点激动,对此感到抱歉,希望没有不好的感觉。
  • @anastaciu 正如我们德国人所说:更聪明的人会屈服。那就是你,我们进行了讨论,没有你的侮辱或道歉的东西,但也许我必须道歉,太
  • 好文明的风格,你们俩。很高兴读到这样的东西。玩得开心。

标签: c++ reference


【解决方案1】:

我不确定这是否适合您的需求,因为它不是语言强加的语法。但是,您可以使用 reference wrapper 在调用方指示 passing-by-reference。具有标准引用包装器的解决方案有一个缺点,它实际上可以在两种情况下使用:

foo(std::ref(x), std::ref(x));  // no error

这是由从int& 到int 的隐式转换引起的。

但是,您可以创建一个自定义引用包装器,它允许转换为存储的引用类型,但阻止转换为相应的值类型。一个基本的示例实现:

template <typename T>
class reference_wrapper
{
  T& ref_;
public:
  reference_wrapper(T& ref) : ref_(ref) { }
  operator T&() const { return ref_; }
  operator T() = delete;
};

template <typename T>
auto ref(T& ref) { return reference_wrapper<T>{ref}; }

现在,这个引用包装器不能在按值传递的上下文中使用:

int x = 1;
foo(std::ref(x), std::ref(x));  // ok
foo(ref(x), ref(x));            // error
foo(ref(x), x);                 // ok

现场演示:https://wandbox.org/permlink/OJJ2hj6F3PB7QzG2。

请注意,编译器似乎足够聪明,可以优化所有开销:https://godbolt.org/z/NiS119。

【讨论】:

  • 只是猜测,但我认为在调用站点没有明确表示法的引用是“问题”,而不是相反。此外,这会用完一个允许的隐式自定义转换,这可能很不方便。
【解决方案2】:

大多数情况下,参数是否通过引用而不是通过值传递,要么是显而易见的(显然是一个外在参数,或者显然需要原始参数),要么是无关紧要的(它只是一种优化)。其余时间,API 要么设计不当,要么您真的应该关心自己在做什么并阅读手册/智能感知/标题。

但这并不是显式标记引用参数(即在调用代码中)会成为巨大障碍的原因:
神奇的词是template。

C++ 模板比 C#/Java 风格的泛型更具表现力,它们形成了自己的图灵完备语言。编写更复杂的模板可能会很困难,而不必迎合“这可能是一个 ref-argument”,并编写额外的变体来标记它。

一个示例模板:

template <class T>
void logged_store(T&& t) {
    std::log << "storing \"" << t << "\"\n";
    storage.store(std::forward<T>(t));
}

如果t 是基本类型(指针、整数、浮点数...),它将按值传递给流插入器。
如果t 是其他任何东西,它可能会通过常量引用传递以避免无用的副本。

【讨论】:

  • 到目前为止,我从未使用模板进行编程,但我可以想象其中的繁琐。你能提供一个小例子来说明问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-29
  • 1970-01-01
  • 2023-03-07
  • 2014-08-23
  • 2015-05-23
  • 2023-03-02
  • 2017-05-17
相关资源
最近更新 更多