3

假设我有一个std::map<std::string, std::vector<T>并且我想写一些代码

给定一些键,这将返回给我映射向量后面的元素。

所以我首先编写了一些代码,它将返回集合末尾的元素(在本例中为向量):

// get element at back of given collection
template<typename Collection>
auto ReturnLastObject(const Collection& collection) -> decltype(collection.back())&
{
    return collection.back();
}

到目前为止,一切都很好。

接下来,我意识到我的函数实际执行逻辑将需要返回相同的类型ReturnLastObject,所以我编写了一些辅助结构,允许我使用类型特征来拉出函数指针的返回类型(预期该函数指针将指向ReturnLastObject<U>):

template<typename T>
struct GetReturnType;

template<typename Ret, typename... Args>
struct GetReturnType<Ret(*)(Args...)>
{
    using type = Ret;
};

仍然做得很好:

最后,我编写了 main 函数来返回最后一个元素,或者抛出异常:

template<typename MapType>
auto GetLastAddedObject(const typename MapType::key_type& key, const MapType& mapCollection)
    -> typename GetReturnType<decltype(&ReturnLastObject<typename MapType::mapped_type>)>::type&
{
    auto& objects = mapCollection.at(key);
    if (!objects.empty())
    {
        return ReturnLastObject(objects);
    }
    else
    {
        throw std::runtime_error("Could not retrieve last added item.");
    }
}

这似乎在GCCClang中都可以正常工作。

但是,当我尝试使用 MSVC 2013(更新 3)进行编译时,出现以下编译器错误:

错误 C2893:无法GetReturnType<unknown-type>::type &detail::GetLastAddedObject(const MapType::key_type &,const MapType &)
        使用以下模板参数专门化函数模板:
        MapType=std::map<std::string,std::vector<int,std::allocator<_Ty>>,std::less<_Kty>,std::allocator<std::pair<const _Kty,std::vector<_Ty,std::allocator<_Ty>>>>>

问题

我要问的是 MSVC 2013 中是否有一种解决方法可以完成同样的事情,或者我只是做错了什么?


编辑:MCVE

(也可以通过 GCC 和 Clang 链接找到)

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <type_traits>
#include <utility>

namespace detail{
// helper struct for peeling off return type of function pointer
template<typename T>
struct GetReturnType;

template<typename Ret, typename... Args>
struct GetReturnType<Ret(*)(Args...)>
{
    using type = Ret;
};

// get element at back of given collection
template<typename Collection>
auto ReturnLastObject(const Collection& collection) -> decltype(collection.back())&
{
    return collection.back();
}

// GetLastAddedObject assumes that MapType is essentially a key mapped to a collection
// and we want to access the collection specified by the key, and return the element at the back of it
template<typename MapType>
auto GetLastAddedObject(const typename MapType::key_type& key, const MapType& mapCollection)
    -> typename GetReturnType<decltype(&ReturnLastObject<typename MapType::mapped_type>)>::type&
{
    auto& objects = mapCollection.at(key);
    if (!objects.empty())
    {
        return ReturnLastObject(objects);
    }
    else
    {
        throw std::runtime_error("Could not retrieve last added item.");
    }
}
} //end namespace detail


int main()
{
    std::map<std::string, std::vector<int>> myMap;
    myMap["StackOverflow"] = {42};
    
    //...
    std::string key = "StackOverflow";
    auto&& lastAddedObject = detail::GetLastAddedObject(key, myMap);
    std::cout << std::forward<decltype(lastAddedObject)>(lastAddedObject) << std::endl; // should print "42
}
4

2 回答 2

1

这对你有用吗?

我没有VS2013来测试它。

namespace detail {

    template<typename MapType>
    typename MapType::mapped_type::value_type GetLastAddedObject(const typename MapType::key_type key, const MapType& mapCollection)
    {
        auto& objects = mapCollection.at(key);
        if (!objects.empty())
        {
            return objects.back();
        }
        else
        {
            throw std::runtime_error("Could not retrieve last added item.");
        }
    }

} //end namespace detail
于 2015-08-28T16:10:52.383 回答
0

您可以简化返回类型:

template<typename MapType>
auto GetLastAddedObject(const typename MapType::key_type& key,
                        const MapType& mapCollection)
-> decltype(ReturnLastObject(mapCollection.at(key)))
于 2015-08-28T16:01:39.203 回答