std:map作为模板参数的模板推导失败

时间:2014-09-26 12:08:57

标签: templates c++11

我在C ++ 11中实现了一个简单的LRU缓存。我几乎已经覆盖了它,但只有一个小问题。让我们说我有以下模板类定义:

#ifndef _LRU_STL_H_
#define _LRU_STL_H_

#include <functional>
#include <cassert>
#include <list>

template <typename KeyType, typename ValueType, template<typename...> class Map>
class LRU {

public:
    typedef Map<KeyType, std::pair<ValueType, typename std::list<KeyType>::iterator>> KeyToValueType;

    LRU(const std::function<ValueType(const KeyType&)> &Function, size_t Capacity)
    : _Function(Function), _Capacity(Capacity) {
        assert(_Capacity != 0);
    }

    ...

private:
    ...

    std::function<ValueType(const KeyType&)> _Function;
    const size_t _Capacity;
    KeyToValueType _KeyToValue;
};

#endif

在KeyToValue类型中,我在MSVC2013中遇到以下编译错误:错误1错误C2976:&#39; std :: map&#39; :模板参数太少c:\ x \ visual studio 2013 \ projects \ caching \ lru_stl \ lru_stl.h 17 1 LRU_STL

第17行是:

typedef Map<KeyType, std::pair<ValueType, typename std::list<KeyType>::iterator>> KeyToValueType;

似乎模板扣除失败。这可能是一个非常简单的问题,但我还是找不到它。为了完整性,这里有一个例子:

std::function<std::string(std::string)> functionToCache = [](std::string & str) {
    std::string reverse;
    reverse.reserve(str.size());

    std::copy(str.begin(), str.end(), reverse);
    return reverse;
};

LRU<std::string, std::string, std::map> LRU(functionToCache, 5);
std::string Hello_World = LRU("Hello World");
assert(Hello_World == "dlroW olleH");

已提供错误。完成提到的修复。仍然出现相同的错误:std :: map太少的模板参数。

只是为了完整性,如果我删除所有内容并创建一个TEST类:

template <typename A, typename B, template <typename ...> class Map>
class TEST {
    typename Map<A, std::pair<B, typename std::list<A>::iterator>> CMAP;
public:
    TEST(void) { }
};

尝试实例化该类会导致完全相同的错误消息。

@Update: VC ++编译器似乎无法在此特定方案中处理默认模板参数。要解决这个问题,我必须将所有四个模板参数添加到typedef中,因此定义变为:

template <typename K, typename V, template <typename...> class Map>
class Test {
    typedef Map<K, std::pair<V, typename std::list<K>::iterator>, std::less<K>, std::allocator<std::pair<const K, typename std::list<K>::iterator>>> MapType;
};

这就是这个问题的全部内容。感谢所有为这位职业绅士提供帮助的人:&#39;我对这个问题一点也不知道,让我们把它扯下来!!!&#39;。你真的很棒!祝你成为最好的男人......

1 个答案:

答案 0 :(得分:1)

你错过了两分。

首先, template template parameter 应该是这样的:

template < parameter-list > class name

所以你的

template<typename...> Map

应该是

template<typename...> class Map

其次,you should use typename with dependent names.在您的代码中,std::list<Key>::iterator是一个从属名称(取决于Key)。因此,您应该使用typename std::list<Key>::iterator代替。


这是我更正的测试代码。

#include <list>
#include <map>

template <typename Key, typename Value,
    template <typename...> class Map>
class Test
{
public:
    typedef Map<
        Key,
        std::pair<Value, typename std::list<Key>::iterator>
        > KeyToValueType;
};

int main()
{
    Test<int, char, std::map>::KeyToValueType asdf;
}

它在g ++ 4.9.1和clang ++ 3.5中都有用。


这似乎是由于VC ++的愚蠢。如果将完整模板参数提供给std::map,包括比较器和分配器,它可能会起作用,因为在这种情况下VC ++似乎无法处理默认模板参数。