27

在 Stroustrup 的 C++ Programming Language book(第 3 版)中,在 Numerics 章节中,他展示了以下代码片段:

void f(valarray<double>& d)
{
    slice_array<double>& v_even = d[slice(0,d.size()/2,2)];
    slice_array<double>& v_odd = d[slice(1,d.size()/2,2)];

    v_odd *= v_even;
    v_even = 0;
}

问题是,v_even并且v_odd是对临时对象的非常量引用,这是不允许的。并尝试编译它会发出错误:

error: non-const lvalue reference to type 'slice_array<double>' cannot bind to a temporary of type 'slice_array<double>'
    slice_array<double>& v_even = d[slice(0,d.size()/2,2)];
                         ^        ~~~~~~~~~~~~~~~~~~~~~~~~

我检查了所有在线可用的勘误表,没有任何内容涉及这个基本问题。我错过了什么吗?自从这本书出版以来,这方面的语言是否发生了变化(不太可能,因为这本书本身提到了反对非常量引用临时变量的规则)?这里发生了什么?


如果我修改函数以使用值而不是引用,例如slice_array<double> v_even = ...,那么这实际上是编译的。然而,事实证明我的本地 C++ 头文件使复制构造函数公开,而 Stroustrup 和各种在线参考(cppreference.com、cplusplus.com)声称复制构造函数是私有的。我认为这意味着这个解决方案是不可移植的。Stroustrup 明确列出了一个带有非引用变量的代码示例,并表示这会产生错误,这一事实进一步强化了这一点。


C++98 规范 ( PDF ) 声明slice_array<T>具有私有复制构造函数。到 2005 年(根据这个规范),大概是作为 C++03 的一部分,这变成了一个公共复制构造函数。

4

2 回答 2

9

原始代码示例似乎存在几个不同的问题,并且书中为许多运算符给出的声明也存在。

我认为“最佳”解决方案如下

void f(valarray<double>& d)
{
    const slice_array<double>& v_even = d[slice(0,d.size()/2,2)];
    const slice_array<double>& v_odd = d[slice(1,d.size()/2,2)];

    v_odd *= v_even;
    v_even = 0;
}

所有操作符slice_array<T>都被定义为const它们不是修改切片本身,而是修改内容。这些在书中被错误地定义为非const

于 2012-08-14T07:58:34.353 回答
4

这似乎是在勘误表中发布的(尽管链接现在已经失效)。

但是谷歌很棒,它显示了像“slice_array& v_even”这样的搜索

Stroustrup:C++ 编程语言第三次印刷的勘误表
www.research.att.com/~bs/3rd_printing4.html
[缓存][分享] 在 Google+ 上共享。
查看帖子。
你公开为此 +1 了。
撤消

void f(valarray<double>& d)
{
    slice_array<double>& v_even = d[slice(0,d.size()/2, 2)];
    slice_array<double>& v_odd  = d[slice(1,d.size()/2,2)];

    v_odd *= 2; // double ...

编辑:-感谢凯文的问题编辑,我可以在 N3092 中清楚地看到它不再是错误(第 26.6.1,第 944 页)

4.引入此类替换类型的实现应提供如下附加函数和运算符:
— 对于每个采用 const valarray& 的函数,应添加采用替换类型的相同函数;
— 对于每个采用两个 const valarray& 参数的函数,应添加采用 const valarray& 和替换类型的每种组合的相同函数。

5.特别是,实现应允许从此类替换类型构造 valarray,并应允许将此类类型的赋值和计算赋值给 valarray、slice_array、 gslice_array、mask_array 和indirect_array 对象。

此外,我的编译器没有给出任何代码问题(目前是 VS 2010),可以完美编译。

于 2012-08-14T06:30:41.500 回答