Reputation: 683
I'm implementing a simple LRU cache in C++11. I pretty much have it covered but there's just one minor problem. Let's say I have the following template class definition:
#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
At KeyToValue type I get the following compilation error with MSVC2013: Error 1 error C2976: 'std::map' : too few template arguments c:\x\visual studio 2013\projects\caching\lru_stl\lru_stl.h 17 1 LRU_STL
The 17th line is:
typedef Map<KeyType, std::pair<ValueType, typename std::list<KeyType>::iterator>> KeyToValueType;
Seems like the template deduction fails. It may be a very simple problem but I just couldn't find it yet. For completeness here's an example:
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");
The error is already provided. Done mentioned fixes. Still the same error occurs: std::map too few template arguments.
Just for completeness if I remove everything and create a TEST class:
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) { }
};
Trying to instantiate the class results in the exact same error message.
@Update: VC++ Compiler seems to be unable to process default template parameters in this particular scenario. To solve the issue I had to add all four template parameters to the typedef and so the definition became like:
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;
};
That would be all to this issue. Thanks for all who tried to help and for that professional gentleman with: 'I don't have even the slightest idea about this question, Let's DOWNVOTE it!!!'. You really are amazing! Wish you the best man....
Upvotes: 0
Views: 5363
Reputation: 10417
Your missed two points.
First, template template parameter should be like this:
template < parameter-list > class name
So your
template<typename...> Map
should be
template<typename...> class Map
Second, you should use typename
with dependent names. In your code, std::list<Key>::iterator
is a dependent name (depending on Key
). So, you should use typename std::list<Key>::iterator
instead.
Here's my corrected test code.
#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;
}
It worked both in g++ 4.9.1 and in clang++ 3.5.
It seems to be due to VC++'s foolishness. It may work if you give the full template parameter to std::map
, including comparer and allocator, since VC++ seems not to be able to process default template parameter in this case.
Upvotes: 1