gpt4 book ai didi

c++ - STL 容器的 Const 锁包装器

转载 作者:太空狗 更新时间:2023-10-29 20:54:27 24 4
gpt4 key购买 nike

我正在尝试为 std::vector 创建一个包装器(或来自 STL 的任何其他容器,如果可能的话)可以“锁定”和“解锁”它所持有的 vector 的 const 状态。

例如,如果我为该包装器创建一个对象,我希望能够执行如下操作:

int main()
{
ConstLockVectorWrapper<int> myWrapper(std::vector<int>{}); // Here I pass an empty vector in the constructor parameters,
// which means that my wrapper will be holding an empty vector

// By default the vector inside my wrapper is not locked,
// I can change its size and the values that it holds

myWrapper.get().push_back(10); // ok
myWrapper.get().push_back(20); // ok
myWrapper.get().at(0) = 5; // ok

print(myWrapper.get()); // Prints 5 20



myWrapper.lock(); // Now I made the vector inside my wrapper unchangable



myWrapper.get().push_back(30); // error, the vector is locked
myWrapper.get().at(0) = 55; // error

print(myWrapper.get()); // ok



myWrapper.unlock(); // Now I can change my vector's size and its values again


_getch();
return 0;
}

我得到的唯一解决方案(不幸的是,这不起作用)是在包装类中创建一个常量引用 ( const std::vector<T> & ) 和一个常规引用​​ ( td::vector<T> & ),并将它们绑定(bind)到主 vector 在我们的包装类中。

所以,这就是我所做的:

template <typename T>
class ConstLockVectorWrapper {
public:
ConstLockVectorWrapper(const std::vector<T> & vec)
: wrappedVector(vec), wrappedVectorRef(wrappedVector), wrappedVectorConstRef(wrappedVector), constLock(false)
{}

void lock()
{
if (constLock) // if the vector is already locked, we just exit the function
return;

// else we lock the vector
constLock = true;
}

void unlock()
{
if (!constLock) // if the vector is already unlocked (changable), we just exit the function
return;

// else we unlock the vector
constLock = false;
}

return_type get() // I need to return a const std::vector<T> & if constLock == true, and std::vector<T> & otherwise, what return type should I put in here?
{
if (constLock)
return wrappedVectorConstRef;
else
return wrappedVectorRef;
}

private:
bool constLock;
std::vector<T> wrappedVector;

// refs
std::vector<T> & wrappedVectorRef;
const std::vector<T> & wrappedVectorConstRef;
};

当然,这是行不通的。只是因为我不知道在我的 get() 的返回类型中放什么功能。

我试过使用尾随返回类型,但没有用:

template <typename T>
class ConstLockVectorWrapper {
public:
// ...

private:
bool constLock;
std::vector<T> wrappedVector;

// refs
std::vector<T> & wrappedVectorRef;
const std::vector<T> & wrappedVectorConstRef;

public:
auto get() -> decltype((constLock ? wrappedVectorConstRef : wrappedVectorRef))
{
if (constLock)
return wrappedVectorConstRef;
else
return wrappedVectorRef;
}
};

我想不出任何实际可行的解决方案,因为我还不太擅长 C++。

所以我请求您帮助解决我的问题。任何解决此问题的建议或提示将不胜感激!

谢谢

附言

我的主要目标是使我的包装器容器类型独立,因此它可以“锁定”和“解锁”它所持有的容器的 const 状态,而与其类型无关。

这是 print()我在第一个代码片段中使用的函数:

template <typename Container>
void print(const Container & c)
{
for (const auto & var : c)
std::cout << var << std::endl;
}

最佳答案

从根本上说,一个方法总是返回相同的东西。同一类型。每次。在 C++ 中,不可能让一个方法有时返回一种类型,而在其他时候返回另一种类型。 C++ 不是这样工作的。

因此,最初的方法是让 get() 返回一个具有状态的代理对象。使用您问题中大致相同的类和名称:

class return_type {

bool is_const;
std::vector<T> &wrapped_vec;

public:
return_type(bool is_constArg,
std::vector<T> &wrapped_vecArg)
: is_const(is_constArg), wrapped_vec(wrapped_vecArg)
{
}

void push_back(T &&t)
{
if (is_const)
throw std::runtime_error(); // Or, whatever...
wrapped_vec.push_back(std::forward<T>(t));
}

// return_type will have to implement, and baby-sit all other
// methods you wish to invoke on the underlying vector.
};

return_type get()
{
return return_type(constLock);
}

这很简单,但很粗糙而且有些乏味。您必须实现您需要在 return_type 代理中使用的每个 std::vector 方法。

更好的方法是利用 C++11 lambda。这将避免以一些额外的代码膨胀为代价重新实现每个轮子的需要。但是,大不了。如今,RAM 很便宜。您现在将在包装器中实现两个模板方法,而不是 get()return_type:get_const()get_mutable( )。它们中的每一个都接受一个 lambda 参数并调用它,如果一切顺利,将包装的 vector 作为参数传递给它:

      template<typename lambda>
void get_mutable(lambda &&l)
{
if (constLock)
throw std::runtime_error(); // Or, whatever...

l(wrapped_vec);
}

template<typename lambda>
void get_const(lambda &&l)
{
l(const_cast<const std::vector<T> &>(wrapped_vec));
}

您现在唯一需要决定的是您是需要访问可变 vector 还是常量 vector ,并选择正确的 getter:

myWrapper.get_mutable( [&](std::vector<int> &v) { v.push_back(10); } );

get_mutable() 如果此时 vector 被锁定则抛出异常。否则它会将 vector 传递给您的 lambda。您的 lambda 做任何它想做的事,可以是 push_back() 或其他任何东西,然后返回。

但如果您只需要对 vector 进行只读访问,请使用 get_const():

int s;

myWrapper.get_const( [&](const std::vector<int> &v) { s=v.size(); } );

请注意,get_const() 会在调用 lambda 之前注意 const_cast vector ,因此 lambda 将无法修改它。这将在编译时强制执行。

通过一些额外的工作,也可以稍微清理一下,让 getter 也返回任何 lambda 返回给调用者,这样就可以做这样的事情:

int s=myWrapper.get_const( [&](const std::vector<int> &v) { return v.size(); } );

可以让 get_const()get_mutable() 足够聪明来判断 lambda 是否返回了一些东西,并愉快地将它传回给调用者,无论这是。我想,如何做到这一点将是 stackoverflow.com 上的另一个问题

附言如果您没有 C++11,您可以让 get_const()get_mutable() 返回包装的 vector (使用 get_mutable()验证它没有被锁定)。这确实完成了同样的事情。关键在于,由于 C++ 的工作方式,您必须提前明确需要常量访问还是可变访问。

关于c++ - STL 容器的 Const 锁包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39090446/

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