簡體   English   中英

使用指針/對象/模板參數校正常數

[英]Correct constness with pointer / object / template parameter

我有一個模板類foo(本質上是一個矩陣)。 foo的模板參數只能是intfloatdouble ,即const int 原因是我有專門的運算符,在const情況下重復運算符似乎很多余。 我有兩個get_data函數,它們返回具有適當常數的指針。 但是,我也不需要選擇單個行並返回const foorow函數,以使調用者無法修改返回的對象。

我的問題:

1)我怎樣才能使B const?

2)我應該為foo做運算符嗎?

2)我應該創建reference_foo類嗎?

template <class T>
class foo
{
    using uint8_t = unsigned char;

    int rows = 0;
    int cols = 0;    
    T * data = nullptr;
    bool reference = false;

public:
    foo() = default;
    //foo(const foo&) // this is not included here for simplicity
    //foo& operator=(const foo&) // this is not included here for simplicity

    foo(int r, int c) : rows(r), cols(c)
    {
        data = new T[rows * cols];
    }

    ~foo()
    {
        if (!reference)
        {
            delete[] data;
        }
    }

    T * get_data()
    {
        return data;
    }

    T const * get_data() const
    {
        return data;
    }

    const foo row(int r) const
    {
        foo t;
        t.rows = 1;
        t.cols = cols;
        t.reference = true;
//        t.data = get_data() + r * cols; // ERROR: invalid conversion from 'const uint8_t*' to 'uint8_t*'
        t.data = const_cast<T*>(get_data()) + r * cols; // Not pretty, but "ok" if the returned object is const
        return t;
    }
};

int main() 
{
    const foo<int> A(2, 1);
//    A.get_data()[0] = 1; // ERROR: assignment of read-only location, perfectly catched by compiler
    auto B = A.row(1);
    B.get_data()[0] = 1; // B is not const... overwritten...

    return 0;
}

為了簡單起見,省略了操作員功能。

這里有2種constness。 常量數據和常量句柄。

我們要做的是從以下四種組合中創造理智:

  • const句柄,const數據= const
  • const句柄,可變數據= const
  • 可變句柄,const data = const
  • 可變句柄,可變數據=可變

此外,將返回值標記為const毫無意義。 返回值是一個r值。 它將被復制或移動。 這不會在調用站點上產生const句柄。

因此,我們需要針對get_data()在2個地方檢測constness。 C ++通過const重載為我們做了第一個。 然后,我們必須推遲到另一個在推論上下文中評估的模板,以便可以使用std::enable_if

#include <cstddef>
#include <utility>
#include <type_traits>

// default getter - element != const element
template<class Element, typename = void>
struct data_getter
{
  using element_type = Element;
  using const_element_type = std::add_const_t<element_type>;

  // detect mutable container    
  element_type* operator()(element_type ** pp) const
  {
    return *pp;
  }

  // detect const container
  const_element_type* operator()(element_type * const * pp) const
  {
    return *pp;
  }


};

// specific specialisation for element == const element    
template<class Element>
struct data_getter<Element,
std::enable_if_t<
  std::is_same<Element, std::add_const_t<Element>>::value>>
{
  // in this case the container's constness is unimportant, so
  // we use const because it means only writing one method
  Element* operator()(Element *const* p) const
  {
    return *p;
  }
};

template <class T>
class foo
{
  public:
  using element = T;
  using const_element = std::add_const_t<element>;

    int rows = 0;
    int cols = 0;    
    element * data = nullptr;
    bool reference = false;

public:
    foo() = default;
    //foo(const foo&) // this is not included here for simplicity
    //foo& operator=(const foo&) // this is not included here for simplicity


    foo(int r, int c) : rows(r), cols(c)
    {
        data = new element[rows * cols];
    }

    ~foo()
    {
        if (!reference)
        {
            delete[] data;
        }
    }

    decltype(auto) get_data()
    {
      // defer to getter
      return data_getter<element>()(&data);
    }

    decltype(auto) get_data() const
    {
      // defer to getter
      return data_getter<const_element>()(&data);
    }

    // this will return a mutable container of const data    
    foo<const_element> row(int r) const
    {
        foo<const_element> t;
        t.rows = 1;
        t.cols = cols;
        t.reference = true;
        t.data = get_data() + r * cols;
        return t;
    }
};

int main() 
{
    foo<int> A(2, 1);
    A.get_data()[0] = 1;

  auto AC = A.row(0);
  auto x = AC.get_data()[0];   // fine

//  AC.get_data()[0] = 1; // assignment of read-only location

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM