gpt4 book ai didi

c++ - 使用指针/对象/模板参数更正常量

转载 作者:行者123 更新时间:2023-11-28 05:24:04 25 4
gpt4 key购买 nike

我有一个模板类 foo(本质上是一个矩阵)。 foo 的模板参数只能是 intfloatdouble,即不能是 const int。这样做的原因是我有专门的运算符来处理这些,并且为 const 情况复制运算符似乎是多余的。我有两个 get_data 函数,它们返回一个具有适当常量的指针。但我也不想要一个选择单行并返回 const foorow 函数,这样调用者就无法修改返回的对象。

我的问题:

1) 如何使 B 为常量?

2) 我是否应该为例如富?

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;
}

为简单起见,省略了运算符函数。

最佳答案

这里有两种常量。常量数据和常量句柄。

我们想要做的是从四种组合中创造理智:

  • 常量句柄,常量数据=常量
  • const 句柄,可变数据 = const
  • 可变句柄,const data = const
  • 可变句柄,可变数据 = 可变

此外,将返回值标记为 const 没有任何意义。返回值是一个右值。它将被复制或移动。这不会在调用站点产生 const 句柄。

所以我们需要在 get_data() 的两个地方检测常量。 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;
}

关于c++ - 使用指针/对象/模板参数更正常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40911574/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com