尝试为 MFC 的 CMap 编写 for_each 算法
Trying to write a for_each algorithm for MFC's CMap
是的,我知道我应该制作一个迭代器,但我需要快速完成此操作,为与 VC++ 相关的任何内容编写适当的迭代器实在令人沮丧。 (这也适用于许多其他标准的东西,并且正在增加我的工作量。:( )
所以我写了一个 for_each() 算法来处理脏话:
template <typename K, typename AK, typename V, typename AV>
void for_each(CMap<K, AK, V, AV>& container, std::function<void(AK, AV)> body)
{
POSITION pos = container.GetStartPosition();
while (pos != NULL)
{
AK key;
AV value;
// Get key and value
container .GetNextAssoc(pos, key, value);
body(key, value);
}
}
但显然VC++无法为函数模板推导出AK和AV。这是正常现象还是 VC++ 的另一个限制?
编辑
这是请求的错误:
1>d:\projects\clean\cv32\cvcustombuttoninfo.cpp(113): error C2784: 'void for_each(CMap<KEY,ARG_KEY,VALUE,ARG_VALUE> &,std::function<void(AK,AV)>)' : could not deduce template argument for 'std::function<void(AK,AV)>' from 'CCVCustomRibbonInfo::WriteFile::<lambda_0513c2955d2b7b0197efcf2b0ce9322b>'
1> d:\projects\clean\cv32\cvcustombuttoninfo.cpp(66) : see declaration of 'for_each'
这似乎也发生在带有 -std=c++11 参数的 gcc 4.9.0 上。
#include <functional>
template <typename T>
void fn(T t, std::function<void(T)>)
{
}
int main()
{
int i;
fn(i, [](int i){});
return 0;
}
以及 g++ 错误:
/tmp/gcc-explorer-compiler115110-34-1cr9oud/example.cpp: In function 'int main()':
11 : error: no matching function for call to 'fn(int&, main()::)'
fn(i, [](int i){});
^
11 : note: candidate is:
4 : note: template void fn(T, std::function)
void fn(T t, std::function<void(T)>)
^
4 : note: template argument deduction/substitution failed:
11 : note: 'main()::' is not derived from 'std::function'
fn(i, [](int i){});
^
Compilation failed
C++ lambda 的类型与具有相同签名的 std::function
不同。这就是模板参数推导失败的原因——它或多或少适用于精确类型。使用 template argument deduction 不考虑转化。您不想在模板参数中使用 std::function
。要强制签名,您可以检查 Func
是否可转换为 std::function<void(AK, AV)>
.
template <typename K, typename AK, typename V, typename AV, typename Func, typename = std::enable_if_t<std::is_convertible<Func, std::function<void(AK, AV)>>::value> >
void for_each(CMap<K, AK, V, AV>& container, Func body)
{
POSITION pos = container.GetStartPosition();
while (pos != NULL)
{
AK key;
AV value;
// Get key and value
container .GetNextAssoc(pos, key, value);
body(key, value);
}
}
你应该做一个迭代器:
#include <iterator>
// std::is_const
template <class T>
struct is_const { static const bool value = false; };
template <class T>
struct is_const<const T> { static const bool value = true; };
// std::conditional_t<C, std::add_const_t<T>, T>
template <bool C, class T>
struct maybe_const { typedef const T type; };
template <class T>
struct maybe_const<false, T> {
typedef T type;
};
template <class CMapType>
class cmap_iterator_base {
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename CMapType::CPair value_type;
typedef typename maybe_const<
is_const<CMapType>::value, value_type
>::type cv_value_type;
typedef cv_value_type& reference;
typedef cv_value_type* pointer;
cmap_iterator_base() : cmap_(0), pos_(0) {}
cmap_iterator_base(CMapType& cmap) : cmap_(&cmap), pos_(cmap.PGetFirstAssoc()) {}
bool operator==(const cmap_iterator_base& other) const {
return pos_ == other.pos_;
}
bool operator!=(const cmap_iterator_base& other) const {
return !(*this == other);
}
cmap_iterator_base& operator++() {
pos_ = cmap_->PGetNextAssoc(pos_);
return *this;
}
cmap_iterator_base operator++(int) {
cmap_iterator_base tmp = *this;
++*this;
return tmp;
}
reference operator*() const {
return *pos_;
}
pointer operator->() const {
return pos_;
}
private:
CMapType* cmap_;
pointer pos_;
};
template <class K, class AK, class V, class AV>
cmap_iterator_base<CMap<K, AK, V, AV> >
begin(CMap<K, AK, V, AV>& cmap) {
return cmap_iterator_base<CMap<K, AK, V, AV> >(cmap);
}
template <class K, class AK, class V, class AV>
cmap_iterator_base<CMap<K, AK, V, AV> >
end(CMap<K, AK, V, AV>&) {
return cmap_iterator_base<CMap<K, AK, V, AV> >();
}
template <class K, class AK, class V, class AV>
cmap_iterator_base<const CMap<K, AK, V, AV> >
cbegin(const CMap<K, AK, V, AV>& cmap) {
return cmap_iterator_base<const CMap<K, AK, V, AV> >(cmap);
}
template <class K, class AK, class V, class AV>
cmap_iterator_base<const CMap<K, AK, V, AV> >
cend(const CMap<K, AK, V, AV>&) {
return cmap_iterator_base<const CMap<K, AK, V, AV> >();
}
代码是纯 C++98,因为我不知道您使用的 Visual C++ 版本实现了哪些 C++11 功能。
是的,我知道我应该制作一个迭代器,但我需要快速完成此操作,为与 VC++ 相关的任何内容编写适当的迭代器实在令人沮丧。 (这也适用于许多其他标准的东西,并且正在增加我的工作量。:( )
所以我写了一个 for_each() 算法来处理脏话:
template <typename K, typename AK, typename V, typename AV>
void for_each(CMap<K, AK, V, AV>& container, std::function<void(AK, AV)> body)
{
POSITION pos = container.GetStartPosition();
while (pos != NULL)
{
AK key;
AV value;
// Get key and value
container .GetNextAssoc(pos, key, value);
body(key, value);
}
}
但显然VC++无法为函数模板推导出AK和AV。这是正常现象还是 VC++ 的另一个限制?
编辑 这是请求的错误:
1>d:\projects\clean\cv32\cvcustombuttoninfo.cpp(113): error C2784: 'void for_each(CMap<KEY,ARG_KEY,VALUE,ARG_VALUE> &,std::function<void(AK,AV)>)' : could not deduce template argument for 'std::function<void(AK,AV)>' from 'CCVCustomRibbonInfo::WriteFile::<lambda_0513c2955d2b7b0197efcf2b0ce9322b>'
1> d:\projects\clean\cv32\cvcustombuttoninfo.cpp(66) : see declaration of 'for_each'
这似乎也发生在带有 -std=c++11 参数的 gcc 4.9.0 上。
#include <functional>
template <typename T>
void fn(T t, std::function<void(T)>)
{
}
int main()
{
int i;
fn(i, [](int i){});
return 0;
}
以及 g++ 错误:
/tmp/gcc-explorer-compiler115110-34-1cr9oud/example.cpp: In function 'int main()':
11 : error: no matching function for call to 'fn(int&, main()::)'
fn(i, [](int i){});
^
11 : note: candidate is:
4 : note: template void fn(T, std::function)
void fn(T t, std::function<void(T)>)
^
4 : note: template argument deduction/substitution failed:
11 : note: 'main()::' is not derived from 'std::function'
fn(i, [](int i){});
^
Compilation failed
C++ lambda 的类型与具有相同签名的 std::function
不同。这就是模板参数推导失败的原因——它或多或少适用于精确类型。使用 template argument deduction 不考虑转化。您不想在模板参数中使用 std::function
。要强制签名,您可以检查 Func
是否可转换为 std::function<void(AK, AV)>
.
template <typename K, typename AK, typename V, typename AV, typename Func, typename = std::enable_if_t<std::is_convertible<Func, std::function<void(AK, AV)>>::value> >
void for_each(CMap<K, AK, V, AV>& container, Func body)
{
POSITION pos = container.GetStartPosition();
while (pos != NULL)
{
AK key;
AV value;
// Get key and value
container .GetNextAssoc(pos, key, value);
body(key, value);
}
}
你应该做一个迭代器:
#include <iterator>
// std::is_const
template <class T>
struct is_const { static const bool value = false; };
template <class T>
struct is_const<const T> { static const bool value = true; };
// std::conditional_t<C, std::add_const_t<T>, T>
template <bool C, class T>
struct maybe_const { typedef const T type; };
template <class T>
struct maybe_const<false, T> {
typedef T type;
};
template <class CMapType>
class cmap_iterator_base {
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename CMapType::CPair value_type;
typedef typename maybe_const<
is_const<CMapType>::value, value_type
>::type cv_value_type;
typedef cv_value_type& reference;
typedef cv_value_type* pointer;
cmap_iterator_base() : cmap_(0), pos_(0) {}
cmap_iterator_base(CMapType& cmap) : cmap_(&cmap), pos_(cmap.PGetFirstAssoc()) {}
bool operator==(const cmap_iterator_base& other) const {
return pos_ == other.pos_;
}
bool operator!=(const cmap_iterator_base& other) const {
return !(*this == other);
}
cmap_iterator_base& operator++() {
pos_ = cmap_->PGetNextAssoc(pos_);
return *this;
}
cmap_iterator_base operator++(int) {
cmap_iterator_base tmp = *this;
++*this;
return tmp;
}
reference operator*() const {
return *pos_;
}
pointer operator->() const {
return pos_;
}
private:
CMapType* cmap_;
pointer pos_;
};
template <class K, class AK, class V, class AV>
cmap_iterator_base<CMap<K, AK, V, AV> >
begin(CMap<K, AK, V, AV>& cmap) {
return cmap_iterator_base<CMap<K, AK, V, AV> >(cmap);
}
template <class K, class AK, class V, class AV>
cmap_iterator_base<CMap<K, AK, V, AV> >
end(CMap<K, AK, V, AV>&) {
return cmap_iterator_base<CMap<K, AK, V, AV> >();
}
template <class K, class AK, class V, class AV>
cmap_iterator_base<const CMap<K, AK, V, AV> >
cbegin(const CMap<K, AK, V, AV>& cmap) {
return cmap_iterator_base<const CMap<K, AK, V, AV> >(cmap);
}
template <class K, class AK, class V, class AV>
cmap_iterator_base<const CMap<K, AK, V, AV> >
cend(const CMap<K, AK, V, AV>&) {
return cmap_iterator_base<const CMap<K, AK, V, AV> >();
}
代码是纯 C++98,因为我不知道您使用的 Visual C++ 版本实现了哪些 C++11 功能。