Reputation: 2136
I am trying to make scoped enumerations in my program comparable to underlying type but the following code does not work. Is it because of poor C++11 standard support in the compiler I am using (VC11) or is it because the code breaks some rules from C++11 standard? In latter case which rules exactly are being broken (references to specific standard clauses are welcome)?
#include <type_traits>
enum class Test: short int { A,B,C };
template<typename E> bool operator != (E e, typename std::underlying_type<E>::type n)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
template<typename E> bool operator != (typename std::underlying_type<E>::type n, E e)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
int main()
{
short int x = 123;
x != Test::B; // compilation error
}
Here is why I think my code should be C++11 compliant. A quote from C++11 standard (14.8.3.1):
For each function template, if the argument deduction and checking succeeds, the template arguments (deduced and/or explicit) are used to synthesize the declaration of a single function template specialization which is added to the candidate functions set to be used in overload resolution. If, >for a given function template, argument deduction fails, no such function is added to the set of >candidate functions for that template.
EDIT. My code is not C++11 compliant (thanks Vaughn Cato and Andy Prowl for explanation). The alternative working code is provided in Andy Prowl's answer.
P.S. After all I ended up making unscoped enums scoped using namespaces:
namespace Test_ {
enum Test { A,B,C };
};
using Test_::Test;
namespace Test2_ {
enum Test2 { Z,Y,B };
};
using Test2_::Test2;
Upvotes: 4
Views: 492
Reputation: 64308
Section 14.8.2 paragraph 8 of the C++11 standard states:
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [ Note: Access checking is done as part of the substitution process. — end note ] Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed. — end note ]
In your case, instantiating underlying_type
causes a failure, but not in the immediate context, so it is not a type deduction failure, so SFINAE does not apply.
Upvotes: 1
Reputation: 126432
You could use SFINAE to rule out the instantiation of the signature of your comparison operators (and therefore the instantiation of std::underlying_type<T>
) when the corresponding argument is not an enumeration:
#include <type_traits>
template<typename E,
typename std::enable_if<std::is_enum<E>::value>::type* = nullptr>
bool operator != (E e, typename std::underlying_type<E>::type n)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
template<typename E,
typename std::enable_if<std::is_enum<E>::value>::type* = nullptr>
bool operator != (typename std::underlying_type<E>::type n, E e)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
Here is a live example.
EDIT:
Since VC11 seems to lack support for default arguments on template parameters of a function template, here is an alternative solution:
template<typename E>
typename std::enable_if<std::is_enum<E>::value, bool>::type
operator != (E e, typename std::underlying_type<E>::type n)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
template<typename E>
typename std::enable_if<std::is_enum<E>::value, bool>::type
operator != (typename std::underlying_type<E>::type n, E e)
{
return static_cast<typename std::underlying_type<E>::type>(e) != n;
}
And a live example of course.
Upvotes: 4