有没有更好的方法来实现成员函数 row() 的 const 版本而不使用 const_cast?

Posted

技术标签:

【中文标题】有没有更好的方法来实现成员函数 row() 的 const 版本而不使用 const_cast?【英文标题】:Is there a better way to implement the const version of member function row() without using const_cast? 【发布时间】:2021-02-07 14:14:22 【问题描述】:

示例来自std::slicestd::slice_array的使用演示:

https://en.cppreference.com/w/cpp/numeric/valarray/slice

https://en.cppreference.com/w/cpp/numeric/valarray/slice_array

我应该如何正确定义成员函数 row() 的 const 版本?以下代码可以编译,但它使用 const_cast。如果您能提出任何建议,我将不胜感激。

#include <iostream>
#include <valarray>
class Matrix 
    std::valarray<int> data;
    int dim;
 public:
    Matrix(int r, int c) : data(r*c), dim(c) 
    int& operator()(int r, int c) return data[r*dim + c];
    std::slice_array<int> row(std::size_t row) 
        return data[std::slice(dim*row, dim, 1)];
    
    const std::slice_array<int> row(std::size_t row) const 
        return const_cast<std::valarray<int>&>(data)[std::slice(dim*row, dim, 1)];
    
;
int main()

    Matrix m(3,3);
    int n = 0;
    for(int r=0; r<3; ++r)
       for(int c=0; c<3; ++c)
           m(r, c) = ++n;
    
    const Matrix m2(m);

    for(int r=0; r<3; ++r) 
        for(int c=0; c<3; ++c) 
            std::cout << m(r, c) << " ";
        
        std::cout << std::endl;
    

    // non-const
    std::slice_array<int> isa = m.row(0);
    std::valarray<int> iva(isa);
    for (auto elem : iva)  std::cout << elem << std::endl; 
    
    // const
    const std::slice_array<int> isa2 = m2.row(0);
    const std::valarray<int> iva2(isa2);
    for (auto elem : iva)  std::cout << elem << std::endl; 

    return 0;

如果成员函数定义如下:

    const std::slice_array<int> row(std::size_t row) const 
        return data[std::slice(dim*row, dim, 1)];
    

然后产生以下错误消息:

valarray_demo.cpp:13:16: error: no viable conversion from returned value of type '__val_expr<__slice_expr<const std::__1::valarray<int> &> >' to function return type 'const std::slice_array<int>'
        return data[std::slice(dim*row, dim, 1)];
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/valarray:1149:28: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from
      '__val_expr<__slice_expr<const std::__1::valarray<int> &> >' to 'const std::__1::slice_array<int> &' for 1st argument
class _LIBCPP_TEMPLATE_VIS slice_array

测试: macOS 卡塔利娜; 苹果 clang 版本 11.0.3 (clang-1103.0.32.29)

【问题讨论】:

【参考方案1】:

请注意,在返回值类型const std::slice_array&lt;int&gt; 中,***const 限定符被编译器忽略,因此实际返回类型为std::slice_array&lt;int&gt;。 The same rule applies to function parameters.

您可能想要对常量元素进行切片,而不是对可变元素进行常量切片。


std::valarray doesn't offer slices to constant elements:

std::slice_array<T> operator[](std::slice slicearr);
std::valarray<T>    operator[](std::slice slicearr) const;

const 版本返回元素的副本,因此根本无法实现将切片返回到常量元素。


std::valarray 是一个奇怪的野兽,长期放弃在 C++ 标准库中支持线性代数的尝试。对于生产代码,您可能喜欢使用 Eigen 库:Eigen is a C++ template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms。

【讨论】:

以上是关于有没有更好的方法来实现成员函数 row() 的 const 版本而不使用 const_cast?的主要内容,如果未能解决你的问题,请参考以下文章

类向量没有成员

11.6 C++构造函数重载

11.6 C++构造函数重载

有没有更好的方法来排序这个查询?

C++11 std::declval实现机制随想

定义类(和嵌套类)成员函数的更好/更整洁/更易读的方法? [复制]