我试图为std::vector
(或STL的任何其他容器,如果可能的话)创建一个包装器,它可以锁定"并且"解锁"它所持有的向量的常量状态。
例如,如果我创建该包装器的对象,我希望能够做到这样的事情:
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引用(const std::vector<T> &
)和一个常规引用(td::vector<T> &
)包装器类,并将它们绑定到包装器类中的主向量。
所以,这就是我所做的:
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 ++。
所以我要求你帮助解决我的问题。任何有关解决此问题的建议或提示都将不胜感激!
由于
我的主要目标是使我的包装容器类型独立,因此它可以锁定&#34;并且&#34;解锁&#34;它所持有的容器的常态,与其类型无关。
这是我在第一个代码段中使用的print()
函数:
template <typename Container>
void print(const Container & c)
{
for (const auto & var : c)
std::cout << var << std::endl;
}
答案 0 :(得分:3)
从根本上说,方法总是返回相同的东西。相同的类型。每次。在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 lambdas。这将避免重新实现每个轮子的需要,代价是一些额外的代码膨胀。但是,很重要。 RAM很便宜,如今。您现在将在包装器中实现两个模板方法,而不是get()
和return_type
,而不是get_const()
和get_mutable()
。 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));
}
和myWrapper.get_mutable( [&](std::vector<int> &v) { v.push_back(10); } );
。它们中的每一个都接受一个lambda参数并调用它,如果一切顺利,将包装的向量作为参数传递给它:
get_mutable()
您现在唯一需要决定的是您是否需要访问可变或常量向量,并选择正确的getter:
push_back()
如果此时向量被锁定, get_const()
会抛出异常。否则它将向量传递给lambda。你的lambda做了它想要的任何东西,可以是int s;
myWrapper.get_const( [&](const std::vector<int> &v) { s=v.size(); } );
,或其他任何东西,然后返回。
但如果您只需要对向量进行只读访问,请使用get_const()
:
const_cast
注意int s=myWrapper.get_const( [&](const std::vector<int> &v) { return v.size(); } );
在调用lambda之前会关注get_const()
向量,因此lambda将无法修改它。这将在编译时强制执行。
通过一些额外的工作,也可以稍微清理一下,让getter也返回lambda返回给调用者的任何东西,这样可以做到这样的事情:
get_mutable()
get_const()
和get_mutable()
可以足够聪明地判断lambda是否返回了某些内容,并愉快地将其传递给调用者,无论它是什么。我想,如何做到这一点必须是stackoverflow.com上的另一个问题
P.S。如果你没有C ++ 11,你可以让get_mutable()
和<?php
$rootCatId= Mage::app()->getStore()->getRootCategoryId();
$categories = Mage::getModel('catalog/category')->getCategories($rootCatId);
$output= '<ul>';
foreach($categories as $category) {
$cat = Mage::getModel('catalog/category')->load($category->getId());
$count = $cat->getProductCount();
$output .= '<li>' . '<a href="' . Mage::getUrl($cat->getUrlPath()) . '">' . $category->getName() . "</a>";
if ($category->hasChildren()) {
$children = Mage::getModel('catalog/category')->getCategories($category->getId());
$array .= get_categories($children);
}
$output .= '</li>';
}
echo $output . '</ul>';
?>
返回包装的向量(document.getElementsByTagName('script')[0].setAttribute('data-url', window.location.href)
验证它没有被锁定)。这真的完成了同样的事情。关键点在于,由于C ++的工作方式,您必须事先消除歧义,无论您是需要持续访问还是可变访问。
答案 1 :(得分:1)
我前段时间正在研究类似的问题。在多线程环境中,根据您是在阅读还是写作,有时可以更有效地使用不同类型的锁。但锁定是完全合作的。可以获得只读锁,但仍然会意外地写入对象。
我正在探索的一个解决方案是,不是从对象获取只读锁,而是获取对象的只读包装,这样不仅是对象只读已锁定,它也只能在对象上调用只读(const
)方法。
我使用的基本包装是这样的:
template<typename T>
class ConstWrapper
{
T& v;
public:
ConstWrapper(T& v): v(v) {}
T const& operator* () const { return v; } // return const reference
T const* operator->() const { return &v;} // return const pointer
};
通过重载*
和->
运算符,您可以获得一种传递的能力来调用所包含的对象方法 - 但是使用指针语义(尽管它不是指针)。
std::vector<int> v {1, 2, 3, 4}; // not const
ConstWrapper<std::vector<int>> cv(v); // const wrapper
std::cout << cv->at(0) << '\n'; // okay at() is a const method
cv->push_back(8); // ILLEGAL!! push_back() is not a const method