如何按类型(不是值)添加使用指向成员值的指针作为模板参数
How to add use a pointer to member value as a template parameter by type (not value)
我的情况:
我经常需要一个结构向量,其中一个字段可以被认为是键或 ID,而不是将它昂贵地存储在地图中(内存使用在这个应用程序中非常重要)我想存储它在一个平面向量中,但提供了一个类似地图的界面,用于按键查找元素。
我对这个问题的第一个解决方案:
template <class T, class Key, class KeyFn>
class TKeyedVector : public std::vector<T>
{
public:
const_iterator find(const Key& key) const {return std::find_if(begin(), end(), [&](const T& entry) {return keyFn(entry)==key; }); }
KeyFn keyFn;
};
struct KeyedDataEntry
{
std::string key;
int value;
struct KeyExtractor {
const std::string& operator()(const KeyedDataEntry& e) const {return e.key; };
};
};
using KeyedDataArray = TKeyedVector<KeyedDataEntry, std::string, KeyedDataEntry::KeyExtractor>;
现在一切正常,但我希望能够通过使用指向嵌入到类型中的成员变量的指针来消除对 KeyExtractor
类型的需要:
template <class T, class Key, Key T::* keyFn>
class TKeyedVector : public std::vector<T>
{
public:
const_iterator find(const Key& key) const {return std::find_if(begin(), end(), [&](const T& entry) {return keyFn(entry)==key; }); }
};
using KeyedDataArray = TKeyedVector<KeyedDataEntry, std::string, &KeyedDataEntry::key>;
但是我无法让它工作。我一直在查看 std::mem_fn
的实现以寻找线索,但我不知道该怎么做。我得到的错误是这样的:
warning C4353: nonstandard extension used: constant 0 as function expression. Use '__noop' function intrinsic instead
有什么线索吗?
编辑:示例版本 http://ideone.com/Qu6TEy
指向成员的指针需要指向成员调用语法的指针。 (entry.*keyFn)()
C++17 将附带一个标准的 std::invoke
函数,使编写此类模板变得不那么烦人(它适用于所有可调用对象)。但与此同时,这就是您需要执行此操作的方式。
这是工作解决方案的开始。您不需要特殊的提取器对象。
注意我封装了向量。假以时日,你会后悔没有这样做的。
#include <vector>
#include <string>
template <class T, class Key, const Key& (T::*Extractor)() const>
class TKeyedVector
{
using storage = std::vector<T>;
using const_iterator = typename storage::const_iterator;
public:
decltype(auto) begin() const
{
return storage_.begin();
}
decltype(auto) end() const
{
return storage_.end();
}
const_iterator find(const Key& key) const
{
return std::find_if(begin(),
end(),
[&](const T& entry)
{
return entry.*Extractor() == key;
});
}
storage storage_;
};
struct KeyedDataEntry
{
std::string key;
int value;
const std::string& get_key() const { return key; }
};
int main()
{
TKeyedVector<KeyedDataEntry, std::string, &KeyedDataEntry::get_key> mymap;
}
但是你这个想法有问题
为了使这个结构成为映射,键必须是不可变的。这仅支持 returning 不可变对象。然后,这立即争论只使用 unordered_set
或 set
.
如果您要 return 引用底层向量中的可变对象,那么您也可以简单地使用 std::find_if
和谓词来查找它们。
我的情况:
我经常需要一个结构向量,其中一个字段可以被认为是键或 ID,而不是将它昂贵地存储在地图中(内存使用在这个应用程序中非常重要)我想存储它在一个平面向量中,但提供了一个类似地图的界面,用于按键查找元素。
我对这个问题的第一个解决方案:
template <class T, class Key, class KeyFn>
class TKeyedVector : public std::vector<T>
{
public:
const_iterator find(const Key& key) const {return std::find_if(begin(), end(), [&](const T& entry) {return keyFn(entry)==key; }); }
KeyFn keyFn;
};
struct KeyedDataEntry
{
std::string key;
int value;
struct KeyExtractor {
const std::string& operator()(const KeyedDataEntry& e) const {return e.key; };
};
};
using KeyedDataArray = TKeyedVector<KeyedDataEntry, std::string, KeyedDataEntry::KeyExtractor>;
现在一切正常,但我希望能够通过使用指向嵌入到类型中的成员变量的指针来消除对 KeyExtractor
类型的需要:
template <class T, class Key, Key T::* keyFn>
class TKeyedVector : public std::vector<T>
{
public:
const_iterator find(const Key& key) const {return std::find_if(begin(), end(), [&](const T& entry) {return keyFn(entry)==key; }); }
};
using KeyedDataArray = TKeyedVector<KeyedDataEntry, std::string, &KeyedDataEntry::key>;
但是我无法让它工作。我一直在查看 std::mem_fn
的实现以寻找线索,但我不知道该怎么做。我得到的错误是这样的:
warning C4353: nonstandard extension used: constant 0 as function expression. Use '__noop' function intrinsic instead
有什么线索吗?
编辑:示例版本 http://ideone.com/Qu6TEy
指向成员的指针需要指向成员调用语法的指针。 (entry.*keyFn)()
C++17 将附带一个标准的 std::invoke
函数,使编写此类模板变得不那么烦人(它适用于所有可调用对象)。但与此同时,这就是您需要执行此操作的方式。
这是工作解决方案的开始。您不需要特殊的提取器对象。
注意我封装了向量。假以时日,你会后悔没有这样做的。
#include <vector>
#include <string>
template <class T, class Key, const Key& (T::*Extractor)() const>
class TKeyedVector
{
using storage = std::vector<T>;
using const_iterator = typename storage::const_iterator;
public:
decltype(auto) begin() const
{
return storage_.begin();
}
decltype(auto) end() const
{
return storage_.end();
}
const_iterator find(const Key& key) const
{
return std::find_if(begin(),
end(),
[&](const T& entry)
{
return entry.*Extractor() == key;
});
}
storage storage_;
};
struct KeyedDataEntry
{
std::string key;
int value;
const std::string& get_key() const { return key; }
};
int main()
{
TKeyedVector<KeyedDataEntry, std::string, &KeyedDataEntry::get_key> mymap;
}
但是你这个想法有问题
为了使这个结构成为映射,键必须是不可变的。这仅支持 returning 不可变对象。然后,这立即争论只使用 unordered_set
或 set
.
如果您要 return 引用底层向量中的可变对象,那么您也可以简单地使用 std::find_if
和谓词来查找它们。