目前我尝试编写一个函数retrieveKeys()
,它给我一个std :: map的键,并将它存储在一些std :: container中。该功能应以两种方式通用:
push_back()
方法)。目前使用此功能的工作原理如下:
std::unordered_map<int, int> testMap;
std::map<int, int> testMap2;
std::vector<int> keys1 = retrieveKeys<std::vector>(testMap);
std::deque<int> keys2 = retrieveKeys<std::deque>(testMap);
std::vector<int> keys3 = retrieveKeys<std::vector>(testMap2);
std::deque<int> keys4 = retrieveKeys<std::deque>(testMap2);
使用以下功能:
template<template<typename...> typename KeyContainer, typename... KeyContainer_Rest,
template<typename...> typename MapContainer, typename K, typename V, typename... MapContainer_Rest>
inline KeyContainer<K, KeyContainer_Rest...> retrieveKeys(const MapContainer<K, V, MapContainer_Rest...>& map)
{
KeyContainer<K, KeyContainer_Rest...> keys;
for (const auto& m : map)
{
keys.push_back(m.first);
}
return keys;
}
如果我不必明确地编写返回类型,那将是很好的。但是当我尝试像
这样的东西时std::vector<int> keys1_ = retrieveKeys(testMap);
/*
error: no matching function for call to 'retrieveKeys'
std::vector<int> keys1_ = retrieveKeys(testMap);
^~~~~~~~~~~~
*/
在使用clang 3.6(C ++ 17)进行编译时,我得到了上述错误。
所以我的问题是:是否可以重写函数,以便编译器可以减少返回类型?
这里再次提供了易于复制的完整代码:
#include <deque>
#include <vector>
#include <unordered_map>
#include <map>
template<template<typename...> typename KeyContainer, typename... KeyContainer_Rest,
template<typename...> typename MapContainer, typename K, typename V, typename... MapContainer_Rest>
inline KeyContainer<K, KeyContainer_Rest...> retrieveKeys(const MapContainer<K, V, MapContainer_Rest...>& map)
{
KeyContainer<K, KeyContainer_Rest...> keys;
for (const auto& m : map)
{
keys.push_back(m.first);
}
return keys;
}
int main()
{
std::unordered_map<int, int> testMap;
std::map<int, int> testMap2;
std::vector<int> keys1 = retrieveKeys<std::vector>(testMap);
std::deque<int> keys2 = retrieveKeys<std::deque>(testMap);
std::vector<int> keys3 = retrieveKeys<std::vector>(testMap2);
std::deque<int> keys4 = retrieveKeys<std::deque>(testMap2);
//std::vector<int> keys1_ = retrieveKeys(testMap);
/*
error: no matching function for call to 'retrieveKeys'
std::vector<int> keys1_ = retrieveKeys(testMap);
^~~~~~~~~~~~
*/
}
答案 0 :(得分:3)
没有。编译器无法告诉返回类型应该是什么,因为它没有可用于确定的信息(您可以在上下文之外调用retrieveKeys()
立即将其分配给您想要的类型的变量)。
但是,您可以使用auto
:
auto keys1 = retrieveKeys<std::vector>(testMap);
auto keys2 = retrieveKeys<std::deque>(testMap);
auto keys3 = retrieveKeys<std::vector>(testMap2);
auto keys4 = retrieveKeys<std::deque>(testMap2);
答案 1 :(得分:3)
template <typename K, typename M>
struct ReturnTypeDeducer
{
const M& map;
ReturnTypeDeducer(const M& m) : map(m) {}
template <template <typename...> typename KeyContainer, typename... KeyContainer_Rest>
operator KeyContainer<K, KeyContainer_Rest...>() &&
{
KeyContainer<K, KeyContainer_Rest...> keys;
for (const auto& m : map)
{
keys.push_back(m.first);
}
return keys;
}
};
template <template <typename...> typename MapContainer, typename K, typename V, typename... MapContainer_Rest>
inline ReturnTypeDeducer<K, MapContainer<K, V, MapContainer_Rest...>> retrieveKeys(const MapContainer<K, V, MapContainer_Rest...>& map)
{
return map;
}
int main()
{
std::unordered_map<int, int> testMap;
std::map<int, int> testMap2;
std::vector<int> keys1 = retrieveKeys(testMap);
std::deque<int> keys2 = retrieveKeys(testMap);
std::vector<int> keys3 = retrieveKeys(testMap2);
std::deque<int> keys4 = retrieveKeys(testMap2);
}
答案 2 :(得分:1)
不,呼叫站点没有返回类型扣除,因为编译器缺少必要的上下文。与例如比较std::make_unique
:
auto derived_ptr = std::make_unique<Derived>(args); // have to specify return type
通常,模板参数推导可以用于提供的模板参数。提供out-parameter将推断出所有内容
template<class InputParam, class OutputParam>
void copy(InputParam const& src, OutParam& dst) { /* bla */ }
// call as:
InputParam src = /* fill */;
OutputParam dst; // empty
copy(src, dst) // template arguments deduced from supplied src, dst
相反,没有它,您必须明确提供模板参数:
template<class InputParam, class OutputParam>
OutputParam copy(InputParam const& src) { OutputParam x; /* bla */ return x; }
// call as:
InputParam src = /* fill */;
auto dst = copy<OutputParam>(src); // InputParam deduced from src, supply OutputParam template argument
相比之下,在定义点,C ++ 14确实有返回类型推论,所以你可以写
template<template<typename...> typename KeyContainer, typename... KeyContainer_Rest,
template<typename...> typename MapContainer, typename K, typename V, typename... MapContainer_Rest>
auto // <-- here
retrieveKeys(const MapContainer<K, V, MapContainer_Rest...>& map)
{
KeyContainer<K, KeyContainer_Rest...> keys;
for (const auto& m : map)
{
keys.push_back(m.first);
}
return keys; // compiler will deduce return-type of retrieveKeys from this
}
答案 3 :(得分:0)
An example of how you can use container::key_type
template <class CONTAINER>
std::vector <typename CONTAINER::key_type>
retrieveKeys(CONTAINER container)
{
std::vector <typename CONTAINER::key_type> keys;
for (auto itr : container)
{
keys.push_back(itr.first);
}
return keys;
}
int _tmain(int argc, _TCHAR* argv[])
{
typedef std::map <int, int> MYMAP;
MYMAP values;
values.insert(std::make_pair(1, 1));
values.insert(std::make_pair(2, 2));
values.insert(std::make_pair(3, 3));
typedef std::vector <typename MYMAP::key_type> KEYVECTOR;
KEYVECTOR keys = retrieveKeys<MYMAP>(values);
for (auto itr : keys)
std::cout << itr std::endl;
}