5

The following code (live demo) works fine on clang/gcc, but fails to compiler on icc and msvc.

The only difference is the use of template parameter pack in class A, whereas class B is given all template parameters explicitly.

What's the correct behavior? Is the code incorrect? Am I missing something? Or is it just the fact that msvc/icc are not standard-compliant?

Update

Compiler versions tested:

Works:

  • gcc 4.7.3, 4.8.1, 4.8.2, 4.9.0, 4.9.2
  • clang 3.3, 3.4.1, 3.5.0, 3.5.1, 3.6.0rc2

Does not work:

  • msvc-12.0 (2013) update 4
  • icc-13.0.1

The code

#include <unordered_map>

template <class Container>
struct A
{};

// the following won't compile on some compilers (msvc, icc)
template <class... Args>              // line 8
struct A<std::unordered_map<Args...>> // line 9
{
};

template <class Container>
struct B
{};

// the following compiles fine
template <class K, class T, class H, class P, class A>
struct B<std::unordered_map<K, T, H, P, A>>
{
};

int main(void)
{
    typedef std::unordered_map<int, int> my_map;
    A<my_map> a;
    B<my_map> b;
    return 0;
}

Error on icc

test-parameter-pack.cpp(9): error: too few arguments for class template "std::unordered_map"

struct A<std::unordered_map<Args...>>
^

test-parameter-pack.cpp(8): warning #885: template parameter "Args" is not used in or cannot be deduced from the template argument list of class template "A<<error-type>>"

template <class... Args>
^

Error on msvc-12.0 update 4

test-parameter-pack.cpp
test-parameter-pack.cpp(9) : error C2976: 'std::unordered_map' : too few template arguments
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE\unordered_map(79) : see declaration of 'std::unordered_map'
test-parameter-pack.cpp(10) : error C3203: 'unordered_map' : unspecialized class template can't be used as a template argument for template parameter 'Container', expected a real type
test-parameter-pack.cpp(8) : error C3211: 'A<int>' : explicit specialization is using partial specialization syntax, use template <> instead
test-parameter-pack.cpp(10) : see declaration of 'A<int>'
8
  • Which version of icc? Commented Feb 20, 2015 at 9:00
  • 1
    I'm genuinely curious to know if template <class K, class... Args> struct B< std::unordered_map<K, Args...> > {}; works on either. Commented Feb 20, 2015 at 9:17
  • 1
    @WhozCraig All the compilers (except from msvc) are available at gcc.godbolt.org (see the live demo). What about template <class K, class... Args> ..., it doesn't work either on msvc/icc-13. Commented Feb 20, 2015 at 9:28
  • 1
    @WhozCraig: template <class K, class... Args> struct B<std::unordered_map<K, Args...> > {};> works for icc/msvc. Commented Feb 20, 2015 at 10:10
  • 1
    Looks OK to me; ICC/MSVC bug, probably. Commented Feb 20, 2015 at 11:33

2 Answers 2

2

I think it has to do with the fact your partial specialisation of A is wrong. The compiler cannot deduce the actual template arguments of the specialised Container.

It looks like you want to do something special (it is a specialisation after all) in case someone instantiates A with std::unordered_map as container type. I got it to compile on your live demo with icc with the following code.

Note that the Container is now a template template parameter, taking an arbitrary amount of template parameters itself. This allows detection of usage of std::unordered_map as actual container type in use. I did simplify a bit in order to reduce to the minimal example.

#include <unordered_map>

template <template <typename...> class Container, typename... Args>
struct A
{};

// the following won't compile on some compilers (msvc, icc)
template <typename... Args>
struct A<std::unordered_map, Args...>
{
};


int main(void)
{
    A<std::unordered_map, int, int> a;
    return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answer, but my actual question is: why my code is wrong (if it is wrong) and which compiler is right?
0

I had similar problem to this with ICC 19.0.1 but with C++17 auto template parameter.

Solution was to split type from value and deduce it separately:

void f(int, int);

//bugged
template<auto F>
struct BindFunc;

template<typename... Args, void(*X)(Args...)> //warning #885: template parameter "Args" is not used in or cannot be deduced from the template argument list of class template "BindFunc<X>"
struct BindFunc<X>
{

};

//correct
template<typename T, T X>
struct BindFunc2Impl;

template<typename... Args, void(*X)(Args...)>
struct BindFunc2Impl<void(*)(Args...), X>
{

};

template<auto F>
struct BindFunc2 : BindFunc2Impl<decltype(F), F>
{

};

//BindFunc<&f> a1; //error
BindFunc2<&f> a2;

https://gcc.godbolt.org/z/gTWzm5

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.