有没有办法使用模板来概括逻辑?带有键参数包的东西。将通过每个嵌套容器,检查对象可用性并在最后返回它或 nullptr 的东西:
需要一点工作(也许比我更专业的人可以让它更简单),但肯定有可能。
举个例子……给定一个自定义类型的traits(和using以简化使用)如下
template <typename T>
struct lastType
{ using type = T; };
template <template <typename...> class C, typename K, typename V>
struct lastType<C<K, V>> : public lastType<V>
{ };
template <typename T>
using lastType_t = typename lastType<T>::type;
你可以递归写Find()如下
// ground case
template <typename V>
V const * Find (V const & val)
{ return &val; }
// recursion case
template <typename C, typename K0, typename ... Ks>
lastType_t<C> const * Find (C const & cnt, K0 && key0, Ks && ... keys)
{
auto mapIt = cnt.find(std::forward<K0>(key0));
if ( mapIt == cnt.cend() )
return nullptr;
return Find(mapIt->second, std::forward<Ks>(keys)...);
}
以下是完整的编译示例
#include <map>
#include <string>
#include <iostream>
#include <unordered_map>
template <typename T>
struct lastType
{ using type = T; };
template <template <typename...> class C, typename K, typename V>
struct lastType<C<K, V>> : public lastType<V>
{ };
template <typename T>
using lastType_t = typename lastType<T>::type;
template <typename V>
V const * Find (V const & val)
{ return &val; }
template <typename C, typename K0, typename ... Ks>
lastType_t<C> const * Find (C const & cnt, K0 && key0, Ks && ... keys)
{
auto mapIt = cnt.find(std::forward<K0>(key0));
if ( mapIt == cnt.cend() )
return nullptr;
return Find(mapIt->second, std::forward<Ks>(keys)...);
}
using typeC = std::map<int,
std::unordered_map<std::string,
std::unordered_map<long,
std::map<char, long long>>>>;
int main ()
{
typeC c;
c[0]["one"][2l]['3'] = 4ll;
auto v = Find(c, 0, "one", 2l, '3');
std::cout << (*v) << std::endl;
static_assert( std::is_same_v<decltype(v), long long const *>, "!" );
}
-- 编辑--
我今天特别笨:正如 krisz 在他的回答中强调的那样(谢谢),三元运算符允许使用 auto 作为返回类型(来自 C++14)。
所以不需要lastType自定义类型特征,Find()可以简单写成
// ground case
template <typename V>
V const * Find (V const & val)
{ return &val; }
// recursion case
template <typename C, typename K0, typename ... Ks>
auto Find (C const & cnt, K0 && key0, Ks && ... keys)
{
auto mapIt = cnt.find(std::forward<K0>(key0));
return mapIt == cnt.cend()
? nullptr
: Find(mapIt->second, std::forward<Ks>(keys)...);
}
对于 C++11,递归情况还需要尾随返回类型;举例
-> decltype(Find(cnt.find(std::forward<K0>(key0))->second, std::forward<Ks>(keys)...))