如何解决在编译时查找 std::map 的重复值 我尝试过的:
我有一个 模板 类 (BiMap
),它用作 双向 地图,用于查找目的,例如enum
值映射到 std::string
等价物,反之亦然。
为了实现这一点,std::string
值必须也必须是唯一的,以防止重复的 std::string
值在搜索过程中返回第一个找到的 enum
键值查找。
template<typename Key,typename Value>
class BiMap {
public:
explicit BiMap(std::initializer_list<std::pair<Key,Value>> &&items) : bimap_{items.begin(),items.end()} {
assert(!HasDuplicates(bimap_));
}
Key GetKeyFromValue(const Value &value) const {
auto it = std::find_if(bimap_.begin(),bimap_.end(),[&value](const std::pair<Key,Value> &kvp) {
return kvp.second == value;
});
return (it != bimap_.end() ? it->first : Key());
}
Value GetValueFromKey(const Key &key) const {
auto it = bimap_.find(key);
return (it != bimap_.end() ? it->second : Value());
}
private:
const std::map<Key,Value> bimap_;
};
我使用一个名为 HasDuplicates
的函数来检查任何重复值:
template<typename Key,typename Value>
bool HasDuplicates(const std::map<Key,Value> &bimap) {
// Create a map to use the values as keys
std::map<Value,Key> value_key_map;
for (auto &kvp : bimap) value_key_map.emplace(kvp.second,kvp.first);
// If there are no duplicate values then the sizes should be the same
std::cout << "HasDuplicates: " << std::boolalpha << (value_key_map.size() != bimap.size()) << std::endl;
return (value_key_map.size() != bimap.size());
}
我可以运行以下示例代码,该代码将在运行时指示是否有任何重复值:
// Test 1: No duplicates
std::cout << "**No duplicates test:**" << std::endl;
const BiMap<std::string,int> bi_map_no_dups({{"foo",1},{"bar",2},{"foobar",3}});
std::cout << "foo: " << bi_map_no_dups.GetValueFromKey("foo") << std::endl;
std::cout << "bar: " << bi_map_no_dups.GetValueFromKey("bar") << std::endl;
std::cout << "foobar: " << bi_map_no_dups.GetValueFromKey("foobar") << std::endl;
// Test 2: Duplicates
std::cout << "**Duplicates test:**" << std::endl;
const BiMap<std::string,int> bi_map_dups({{"foo",1}});
std::cout << "foo: " << bi_map_dups.GetValueFromKey("foo") << std::endl;
std::cout << "bar: " << bi_map_dups.GetValueFromKey("bar") << std::endl;
std::cout << "foobar: " << bi_map_dups.GetValueFromKey("foobar") << std::endl;
输出结果为:
**No duplicates test:**
HasDuplicates: false
foo: 1
bar: 2
foobar: 3
**Duplicates test:**
HasDuplicates: true
main.cpp:22: BiMap<Key,Value>::BiMap(std::initializer_list<std::pair<_T1,_T2> >&&) [with Key = std::basic_string<char>; Value = int]: Assertion `!HasDuplicates(bimap_)' failed.
可以在here找到上述代码的工作示例。
问题:
如何在编译时评估 std::map
是否有重复值?
我尝试过的:
我已经尝试实现 constexpr
模板函数,如 here:
template <typename K,typename V> constexpr bool has_duplicates(const std::map<K,V> *map)
{
std::map<V,K> value_key_map;
for(auto &kvp : map) value_key_map.emplace(map->second,map->first);
return map->size() == value_key_map.size();
}
int main() {
// Cannot get this part to work
constexpr std::map<std::string,int> bimap({{"foo",1}});
static_assert(!has_duplicates(&bimap));
return 0;
}
注意:我正在使用C++11,但我还不能声明本地变量和循环在 constexpr 函数内部,因此应该恢复到递归,如 here 所示。但是,对于这个例子,如果我能找到一个具有 C++14 的 constexpr 特性的合适的解决方案,我会很高兴,我稍后会得到一个递归版本(如果可能).
解决方法
如何在编译时评估 std::map 是否具有重复值?
你不能。 std::map()
在编译时不可用。
您可以改为使用 https://github.com/serge-sans-paille/frozen 或 https://github.com/mapbox/eternal 进行检查(或其他一些 constexpr 结构)。
另一种方法(如果您想停留在 C++11 级别)是构建基于模板元编程的地图,例如 this answer。
,在评论部分的帮助下,我能够为我的问题制定合适的解决方案。
重要:std::map
不是 constexpr
,不能用于在编译时评估其内容。
但是,您可以使用 std::array<std::pair<const K,V>,N>
在编译时从 C++14 帮助评估内容,如下所示:
template<typename K,typename T,size_t N>
constexpr bool has_duplicates(const std::array<std::pair<K,T>,N> *arr) {
for (int i = 0; i < N - 1; i++) {
for (int j = i + 1; j < N; j++) {
if (compare_equal((*arr)[i].second,(*arr)[j].second) ||
compare_equal((*arr)[i].first,(*arr)[j].first)) return true;
}
}
return false;
}
使用:
constexpr std::array<std::pair<int,const char *>,3> arrd{{ {1,"foobar"},{2,"bar"},{3,"foobar"}}};
static_assert(!has_duplicates(&arrd),"Duplicates Found!");
并且您需要以下额外的比较函数:
template<typename A,typename B>
constexpr bool compare_equal(A a,B b) {
return a == b;
}
template <>
constexpr bool compare_equal(const char * a,const char * b) {
return *a == *b && (*a == '\0' || compare_equal(a + 1,b + 1));
}
对于 C++11 支持,您需要将 has_duplicates
函数更改为递归实现。这是两个版本的完整运行 example。
因此,您可以在类中使用它来在编译时检查重复值。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。