0

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....

Wrath
  • 673
  • 9
  • 32
  • 3
    Show the use site as well. Always post an [MCVE](http://stackoverflow.com/help/mcve) when asking about compilation issues. – Angew is no longer proud of SO Sep 26 '14 at 12:16
  • [MCVE](http://stackoverflow.com/help/mcve) doesn't mean part of the whole code that makes error. It should be **Minimal, Complete, and Verifiable** example. – ikh Sep 26 '14 at 12:24

1 Answers1

1

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.

Community
  • 1
  • 1
ikh
  • 10,119
  • 1
  • 31
  • 70
  • Thanks for the tips. The class before Map was my typo, the typename wasn't there. Modified as you wrote, still the very same error. – Wrath Sep 26 '14 at 13:06
  • @Joey Then, what was the error message and what do you use the version of compiler? I guess It's because VC++ is against the standard in this case – ikh Sep 26 '14 at 13:14
  • The error message is exactly the following: error C2976: 'std::map': too few template arguments The actual version of my compiler is: Microsoft (R) C/C++ Optimizing Compiler Version 18.00.30723 for x86 – Wrath Sep 26 '14 at 13:20
  • @Joey Was it the *whole* error message? vcpp should make more messages >o< Anyway, I guess it's because `std::map`'s additional template parameters, which are comparer and allocator. Try giving them manually. – ikh Sep 26 '14 at 13:26
  • Yes, that's the very whole error message, Ctrl+c -> Ctrl+v directly from Visual Studio. Nothing more, nothing less... I don't pass any Allocator directly to the Map. It has a Key and an std::pair as its Value. Even by using: typename Map KeytoValueType; it fails with the very same error message... – Wrath Sep 26 '14 at 13:30
  • @Joey 1. No, it's maybe not the whole message. please see the "output" window. 2. I said to try passing `std::map` comparer and allocator *directly*. `std::map` actually has **4** template parameters including those, and I guess VC++ can't process default template argument correctly in this case. – ikh Sep 26 '14 at 15:05
  • You were right. VC++ couldn't process the default template arguments in this particular case. Adding the comparator and allocator manually solved the problem. I'll update the original post, if you could add this bit of information to your answer, I'll accept it. Thanks for your help. – Wrath Sep 27 '14 at 09:38