3
votes

I was trying to do template specialization with values, one incarnation being bool, while the other being enum class. I was fighting with the compiler for a day, but did not manage to overcome the "Ambiguous call to overloaded function" error. That code is ugly and rather long, but here is a simple test case:

#include <iostream>

enum class Foo { Bar };
enum class Waldo { Fred };

template<Foo ARG, typename... _Types>
inline bool DOIT( _Types&&... _Args )
{
    return true;
}

template<Waldo ARG, typename... _Types>
inline bool DOIT( _Types&&... _Args )
{
    return false;
}

int main()
{
    std::cout << DOIT<Foo::Bar>() << std::endl;
    std::cout << DOIT<Waldo::Fred>() << std::endl;
    return 0;
}

Both clang 3.8 and gcc 4.8.3 compiles this without a hitch, with the standard being set to c++11, but MSVC keeps firing me the C2668 error message.

AFAIK one reason for enum class was to avoid implicit conversion, but don't know for sure. Is this a compiler error, or some deficiency in the standard?

1
Considering your use of a scoped enum, definitely a MSVC hiccup. - StoryTeller - Unslander Monica
The clang compiler built into Visual Studio says "error : definition with same mangled name as another definition". Reminds me of an old VC++ bug where they mangled the name with the function parameter types, and not with the template types. Perhaps this problem is still alive? - Bo Persson

1 Answers

5
votes

Technically the code you posted is an ill-formed program no diagnostic required because you used an identifier starting with an _ followed by an upper case letter. Such identifiers are reserved by the standard for your compiler's implementors.

But that isn't your problem.


I have seen one case ever where MSVC got it right while both gcc and clang got it wrong when following the standard.

On top of that, the ambiguity makes no sense here.

Your compiler is busted.

A way that should work is:

template<Foo ARG, typename... Ts>
inline bool DOIT( std::integral_constant<Foo, ARG>, Ts&&... args )
{
  return true;
}
template<Waldo ARG, typename... Ts>
inline bool DOIT( std::integral_constant<Waldo, ARG>, Ts&&... args )
{
    return false;
}

int main()
{
    std::cout << DOIT(std::integral_constant<Foo, Foo::Bar>{}) << std::endl;
    std::cout << DOIT(std::integral_constant<Waldo, Waldo::Fred>{}) << std::endl;
    return 0;
}

which works on this online MSVC compiler.