I am trying to use a std::bitset with an enum but I am getting a compilation error saying
template argument 1 is invalid
Funny thing is that when I use any of the enumerated value without the enumeration scope it works fine.
Do you know why?
Below the code
enum MyTypes {
Alpha = 1,
Beta = 2,
Gamma = 3
};
std::bitset<MyTypes::Alpha> bitset_wrong; // It doesn't compile.
std::bitset<Alpha > bitset_good; // It works.
It seems that you have an old compiler that does not support specifying qualified names with unscoped enumerators.
Update your compiler.:)
The code you showed is a valid code according to the C++ 2011 Standard.
Here is a quote from the C++ Standard with an example (7.2 Enumeration declarations)
11 Each enum-name and each unscoped enumerator is declared in the
scope that immediately contains the enum-specifier. Each scoped
enumerator is declared in the scope of the enumeration. These names
obey the scope rules defined for all names in (3.3) and (3.4).
[ Example:
enum direction { left=’l’, right=’r’ };
void g() {
direction d; // OK
d = left; // OK
d = direction::right; // OK
}
Related
What happens when:
I declare and define a name X (either object or type) in the global scope.
I start writing a class. Inside the class, but outside of function bodies etc., I use X.
Later in the class, I declare name X again.
On the Class Scope page on cppreference.com, this is considered undefined behavior. The code snippet looks like this:
typedef int c; // ::c
enum { i = 1 }; // ::i
class X {
char v[i]; // Error: at this point, i refers to ::i
// but there is also X::i
int f() {
return sizeof(c); // OK: X::c, not ::c is in scope inside a member function
}
char c; // X::c
enum { i = 2 }; // X::i
};
typedef char* T;
struct Y {
T a; // Error: at this point, T refers to ::T
// but there is also Y::T
typedef long T;
T b;
};
But in Chapter 3.1 of Stanley B. Lippman's book Inside the C++ Object Model, the compiler should raise an error.
His comments:
In the following code fragment, for example, the type of length in both
member function signatures resolves to that of the global typedef—that is, to int. When the subsequent declaration of the nested typedef of length is encountered,
the Standard requires that the earlier bindings be flagged as illegal
His code snippet looks like this:
typedef int length;
class Point3d {
public:
// oops: length resolves to global
// ok: _val resolves to Point3d::_val
void mumble( length val ) { _val = val; }
length mumble() { return _val; }
private:
// length must be seen before its first reference within the class.
// This declaration makes the prior reference illegal.
typedef float length;
length _val;
};
I tested with clang 7.0.0, there is no warning or error, and the length seems to bind to int. I understand that compiler testing results cannot be used to analyze UBs, so I'm asking this question.
Who is right? Or if they are both right, what am I missing? What does the current standard say about this?
The question already points to the proper cppreference snippet [Class Scope]:
The potential scope of a name declared in a class begins at the point of declaration and includes the rest of the class body and all function bodies ...
Then on the same cppreference page:
If a name is used in a class body before it is declared, and another declaration for that name is in scope, the program is ill-formed, no diagnostic required.
According to the above it sounds like gcc is right with the error and clang is also right (as no diagnostic is required) but is being too permissive allowing ill formed code to compile.
The relevant wording in the spec [basic.scope.pdecl] 6.4.2/1 - Point of Declaration:
... The point of declaration for an enumeration is immediately after the identifier (if any) in either its enum-specifier ([dcl.enum]) or its first opaque-enum-declaration ([dcl.enum]), whichever comes first. The point of declaration of an alias or alias template immediately follows the defining-type-id to which the alias refers.
And [basic.scope.declarative] 6.4.1/4.2:
exactly one declaration shall declare a class name or enumeration name that is not a typedef name and the other declarations shall all refer to the same variable, non-static data member, or enumerator, or all refer to functions and function templates; in this case the class name or enumeration name is hidden ([basic.scope.hiding]).
Then [basic.scope.class] 6.4.7/2 - Class scope:
A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.
Bottom line: this code is ill formed (and thus if compiled can be viewed as undefined behavior), however the compiler can ignore it as no diagnostic is required.
They're both right.
As the article you referenced states, this does not have undefined behaviour, but is rather ill-formed, no diagnostic required.
This is a very specific phrase in the standard, with a very specific meaning, which correlates to exactly what you've seen: the program is ill-formed, but the implementation doesn't have to diagnose that if it doesn't want to.
So, you may get an error, you may not. Everything's fine.
But fix your code. 🙂
The C++14 (precisely, N4296) says with respect to enumerations, in 7.2:11:
Each enum-name and each unscoped enumerator is declared in the scope
that immediately contains the enum-specifier.
Now what happens if a namespace N contains an opaque-enum-declaration of an enum E, and later the enumeration is fully declared from the global namespace? Shall we find its enumerators in the global namespace, or in the namespace N?
Of course, in order to opaque-declare an unscoped enumeration, it shall have a fixed underlying type. Consider the following piece of code.
namespace N { enum E : int; }
enum N::E : int {A,B};
namespace N {
int foo() {
return int(::N::B);
}
}
int bar() {
//return int(::A);
return int(A);
}
The first line in bar is commented out, because clang++ -std=c++14 says:
no member named 'A' in the global namespace; did you mean simply 'A'?
Gcc fails to compile both lines in bar(). So both gcc and clang declare the enumerations in the namespace N.
So my questions are:
What is the scope that immediatelly contains the enum specifier? (I thing it is the scope of the global namespace).
Should the enumerators A, B be defined in the global namespace?
In the bar function, why ::A does not refer to the enumerator, but simple A does?
Why the expression ::N::B in the function N::foo denotes the enumerator?
EDIT 1: the original declaration was enum ::N::E : int {A,B};, but gcc was not able to parse it (bug report), so I removed the leading colons to use enum N::E : int {A,B};
EDIT 2: the clang's behavior is a bug
The enumeration E is declared within the namespace N, even though its definition is set within the global namespace. As such, it can only be accessed in the scope of N.
The bar function should then be defined as:
int bar() {
return int(N::A);
//SAME AS --> return int(::N::A);
}
What is the point of declaration of enumeration types? Is it immediately after the name of an enumeration? I saw Standard C++ 14 (n4296) §3.3.2/3:
The point of declaration for an enumeration is immediately after the
identifier (if any) in either its enum-specifier (7.2) or its first
opaque-enum-declaration (7.2), whichever comes first
But when I try to reproduce it;
template <class T>
struct CL
{
using UndType = int;
};
enum class E: CL<E>::UndType; //error: E is undefined
I have got an error on all the compilers, although enum-base for enumeration E is placed after the identifier and must be visible.
The following;
enum class E : CL<E>::UndType;
Is not accepted as a valid declaration in some current implementations (tested clang++, g++ and MSVC). They do not accept the, as yet incomplete type E, in the enum-base CL<E>::UndType. The error given in the tested implementations is that E is undeclared at that point. They seem to place the point of declaration at the end of the enum-base, they consider it declared once it is complete.
When reading the specifications;
§14.3.1/2 Template type arguments
[ Note: A template type argument may be an incomplete type (3.9). — end note ]
And
§7.2/6 Enumeration declarations
An enumeration whose underlying type is fixed is an incomplete type from its point of declaration (3.3.2) to immediately after its enum-base (if any), at which point it becomes a complete type.
Does hint at it being compilable; as is the case with CRTP implementations.
I'm note sure if this (i.e. the failure to compile enum class E : CL<E>::UndType;) is the intention or if it was considered as a use case. From the specification, the opaque enum declaration is given some "special" treatment w.r.t. its base type and the requirement that it must be an integral type.
Presumably, the code should be compilable given the resolution to CWG#1482.
As for current workarounds...
This;
enum class E; // default underlying type is int
Is the minimum declaration.
The opaque declaration could be either;
enum class E : int; // int base
The following would be a full definition (including enumerators);
enum class E : int {/*...*/};
Or to use the class template, another type (possibly void) could be used.
enum class E : CL<void>::UndType;
Now CWG2516 is opened for this.
I believe it's a bug in the Standard which forbids a portable implementation of is_scoped_enum.
Given a C++11 enum class, nested inside several long- and ugly-named namespaces:
namespace
long_and_ugly
{
enum class
colour
{
red,
green,
blue
};
}
Can aliases be made of the enumeration values? With clang++ 3.5, it is possible to do what follows:
using long_and_ugly::colour; // take all the values into the current namespace
using long_and_ugly::colour::red; // take only 'red' into the current namespace
function_taking_colour_argument( red ); // instead of fully referring to the value
g++ 4.9, however, complains. I can't copy its error message because I can't access the code, but it explicitly complained about the usage of the using directive or declaration. I have also tried this:
using red = long_and_ugly::colour::red;
But it also failed. I'm sorry for not pasting the errors. Nevertheless, I believe you should be able to reproduce it.
Question(s)
Is it possible to declare aliases to enumeration values in standard C++11, or was I using a clang extension?
If it is, what is the correct syntax?
Enumerators in using-declarations
The problem is that the standard says that you shall not refer to an enumerator inside an enum class when using specifying a using-declaration.
7.3.3p7 The using declaration [namespace.udecl] (n3337)
A using-declaration shall not name a scoped enumerator.
namespace N {
enum class E { A };
}
using N::E; // legal
using N::E::A; // ill-formed, violation of [namespace.udecl]p7
Note: clang does accept both lines above; here's a relevant bug report.
It's perfectly fine to refer to the actual name of the enum class itself, but trying to refer to one of its enumerators is ill-formed.
Enumerators in alias-declarations
The standard says that an alias-declaration can only be used to refer to a type-name, since an enumerator isn't a type, using one in such context is ill-formed.
namespace N {
enum class E { A };
}
using x = N::E; // legal, `N::E` is a type
using y = N::E::A; // ill-formed, `N::E::A` isn't a type
Alternatives to using- and alias-declarations
You could declare a constant having whatever-name-of-your-choice initialized with the value you'd like to "alias":
namespace N {
enum class E { A };
}
constexpr N::E x = N::E::A;
int main () {
N::E value = x; // semantically equivalent of `value = N::E::A`
}
Sort of:
namespace long_and_ugly {
enum class colour
{
red,
green,
blue
};
}
const colour red = long_and_ugly::colour::red;
This code compiles (and appears to work) with both GCC and Clang:
#include <iostream>
struct Foo {
enum { number = 42 };
};
int main()
{
Foo bar;
std::cout << bar.number << std::endl;
}
See it here.
It was surprising to me that the compiler accepts bar.number; all text books I can find teach to use Foo::number to access the enumerated value.
Is this code valid? Note that GCC gives a weird warning ("variable 'bar' set but not used"), while Clang doesn't complain about it.
It's perfectly valid:
[C++11: 7.2/10]: Each enum-name and each unscoped enumerator is declared in the scope that immediately contains the enum-specifier. Each scoped enumerator is declared in the scope of the enumeration. These names obey the scope rules defined for all names in (3.3) and (3.4). [..] An enumerator declared in class scope can be referred to using the class member access operators (::, . (dot) and -> (arrow)), see 5.2.5.
The same text (minus rules for scoped enums) can be found in the C++03 standard, at the same location.
I have to admit, this surprises me somewhat as well. I'd have expected :: to be the only valid mechanism.
The warning you get in GCC is not about the use of the enum, but about the fact that you use nothing but the enum. In such a case, you'd typically write Foo::number and avoid instantiating a Foo instance.
Just a guess here:
Since the enum is technically a type, Foo::number could be treated as a const or static const by the compiler. What would happen if you:
#include <iostream>
using namespace std;
enum { number = 42 };
int main()
{
std::cout << number << endl;
}
In this case, number appears to have been resolved to an immediate, and is valid within both this-> and type. scopes.
As I said, this is just a guess. #LightnessRacesInOrbit has spec quotes. He/She/Insanely-well-informed Turing Machine wins.