I have the following enum:
__atttribute__((visibility ("default") )) enum MSG
{
OK,
FAIL,
};
When I compile, it gives me the warning:
warning: attribute ignored in declaration of ‘enum MSG’
warning: attribute for ‘enum MSG’ must follow the ‘enum’ keyword
When I put the attribute after the enum, I get the following errors:
warning: type attributes are honored only at type definition
error: use of enum ‘MSG’ without previous declaration
error: expected unqualified-id before ‘{’ token
Can anyone tell me how to fix this?
The visibility attribute applies to symbols like functions and variables. A definition of an enumeration type that doesn't contain a variable name doesn't create any symbols.
Enumeration type without a variable:
enum msg { OK, FAIL };
An enumeration variable:
enum msg message;
Enumeration type together with a variable:
enum msg { OK, FAIL } message;
In the first case, there's no symbol the visibility attribute could affect at all.
You can fix this by declaring the type of your enum like this:
enum class MSG : std::uint32_t __atttribute__((visibility ("default") ))
{
OK,
FAIL,
};
Though it seems like this is a bug in GCC that was fixed in versions 6+. Related SO post
Related
I'm reading the source code of the main json11 header file.
It contains the following declaration:
template <class T, class = decltype(&T::to_json)>
Json(const T & t) : Json(t.to_json()) {}
I'm trying to find some documentation about this usage of decltype and class inside a template declaration but no success.
Does this construction/usage has a name in C++? Any good reference about it?
It's using SFINAE ("Substitution Failure Is Not An Error"), a common technique for advanced template stuff. In this case, it's used as a crude(1) test whether the type T has a function named to_json.
How it works: if the expression T::to_json is well-formed (there is something named to_json inside the type T), decltype(T::to_json) denotes a valid type and the constructor template can be used normally.
However, if T::to_json is ill-formed (i.e. if there is no to_json member inside T), it means substituting the template argument for T has failed. Per SFINAE, this is not an error of the entire program; it just means that the template is removed from further consideration (as if it was never part of the class).
The effect is thus that if type T has a member to_json, you can use an object of type T to initialise a Json object. If there is no such member in T, the constructor will not exist.
(1) I'm saying crude test because this only checks that T has such a member. It doesn't check that the member is a function which can be invoked without arguments and returns something another constructor of Json can accept. A tighter-fitting test might look something like this:
template <class T, class = std::enable_if_t<std::is_constructible<Json, decltype(std::declval<const T>().to_json())>::value>>
Json(const T & t) : Json(t.to_json()) {}
[Live example]
The code below contains a reference to Enum::name (notice no type parameter).
public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), Enum::name);
}
public static <T, R> ColumnType<T, R> simpleColumn(BiFunction<JsonObject, String, T> readFromJson,
Function<T, R> writeToDb) {
// ...
}
Javac reports a warning during compilation:
[WARNING] found raw type: java.lang.Enum missing type arguments for
generic class java.lang.Enum
Changing the expression to Enum<T>::name causes the warning to go away.
However Idea flags the Enum<T>::name version with a warning that:
Explicit type arguments can be inferred
In turn Eclipse (ECJ) doesn't report any problems with either formulation.
Which of the three approaches is correct?
On one hand raw types are rather nasty. If you try to put some other type argument e.g. Enum<Clause>::name will cause the compilation to fails so it's some extra protection.
On the other hand the above reference is equivalent to e -> e.name() lambda, and this formulation doesn't require type arguments.
Enviorment:
Java 8u91
IDEA 15.0.3 Community
ECJ 4.5.2
There is no such thing as a “raw method reference”. Whilst raw types exist to help the migration of pre-Generics code, there can’t be any pre-Generics usage of method references, hence there is no “compatibility mode” and type inference is the norm. The Java Language Specification §15.13. Method Reference Expressions states:
If a method or constructor is generic, the appropriate type arguments may either be inferred or provided explicitly. Similarly, the type arguments of a generic type mentioned by the method reference expression may be provided explicitly or inferred.
Method reference expressions are always poly expressions
So while you may call the type before the :: a “raw type” when it referes to a generic class without specifying type arguments, the compiler will still infer the generic type signature according to the target function type. That’s why producing a warning about “raw type usage” makes no sense here.
Note that, e.g.
BiFunction<List<String>,Integer,String> f1 = List::get;
Function<Enum<Thread.State>,String> f2 = Enum::name;
can be compiled with javac without any warning (the specification names similar examples where the type should get inferred), whereas
Function<Thread.State,String> f3 = Enum::name;
generates a warning. The specification says about this case:
In the second search, if P1, ..., Pn is not empty and P1 is a subtype of ReferenceType, then the method reference expression is treated as if it were a method invocation expression with argument expressions of types P2, ..., Pn. If ReferenceType is a raw type, and there exists a parameterization of this type, G<...>, that is a supertype of P1, the type to search is the result of capture conversion (§5.1.10) applied to G<...>;…
So in the above example, the compiler should infer Enum<Thread.State> as the parametrization of Enum that is a supertype of Thread.State to search for an appropriate method and come to the same result as for the f2 example. It somehow does work, though it generates the nonsensical raw type warning.
Since apparently, javac only generates this warning when it has to search for an appropriate supertype, there is a simple solution for your case. Just use the exact type to search:
public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), T::name);
}
This compiles without any warning.
I have a problem with enum classes, QVariants and the QSettings class. There are enum class values that I want to store within a QVariant which goes into a QSettings instance. So, my code actually looks something like this:
enum class Foo
{
Bar1, Bar2
}
Q_ENUMS(Foo)
Q_DECLARE_METATYPE(Foo)
...
Foo value = Bar2;
QSettings settings;
settings.setValue(QString("Foo"), QVariant::fromValue(value));
At this point in executing the code, an assertion jumps in and complains:
ASSERT failure in QVariant::save: "Invalid type to save", file kernel\qvariant.cpp
Searching the internet, I found out that the class is missing a fitting << and >> operator. But that is not an option for enum classes. I even tried to use
qRegisterMetaType<Foo>("Foo");
but it did not help. Maybe you have some other suggestions/solutions for me. Thanks!
Enums, which are masked unsigned ints, seem to be a problem, see
Qt4 QSettings save enumeration value (for example Qt::CheckState)
The solution there and probably here would be to convert it an unsigned. To check if the static_cast-result back to the enum is valid you might add Foo_lowest and Foo_highest values to the beginning and end of the enum range.
You can use Q_ENUM since Qt 5.5 and not worry about calling qRegisterMetaType():
enum class Foo
{
Bar1, Bar2
}
Q_ENUM(Foo)
...
Foo value = Foo::Bar2;
QSettings settings;
settings.setValue(QString("Foo"), QVariant::fromValue(value));
Consider the following code:
int main (void) {
int i = xyzzy();
return i;
}
int xyzzy (void) {
return 42;
}
Now, although the prototype for xyyzy is unkown at the point of use, this works in c89 mode because the default return type of a function that has no prototype is int so the implicit function prototype and actual function are compatible.
And, in fact, if you change the return type of the function to float, you get (as expected):
testprog.c:6: error: conflicting types for 'xyzzy'
testprog.c:2: error: previous implicit declaration of 'xyzzy' was here
because the implicit prototype and actual function no longer match.
The original code compiled with gcc --std=c89 --pedantic -Wall -Wextra only gives me the warning:
testprog.c: In function 'main':
testprog.c:2: warning: implicit declaration of function 'xyzzy'
which is expected, because c89 has this to say in 3.7.1 Function definitions:
extern int max(int a, int b) { ... }: Here extern is the storage-class specifier and int is the type specifier (each of which may be omitted as those are the defaults).
and in 3.3.2.2 Function calls:
If the expression that precedes the parenthesized argument list in a function call consists solely of an identifier, and if no declaration is visible for this identifier, the identifier is implicitly declared exactly as if, in the innermost block containing
the function call, the declaration extern int identifier(); appeared.
So the use of a function before declaring it definitely results in the default prototype being created.
However, both those phrases have been removed in c99 and we instead find in 6.5.2.2 Function calls (my bold):
If the expression that denotes the called function has type pointer to function returning an object type, the function call expression has the same type as that object type, and has the value determined as specified in 6.8.6.4. Otherwise, the function call has type void.
I understand it to mean that, if there's no declaration in view when you try to call a function, it's implicitly declared with a void return type.
Yet, when compiling with gcc --std=c99 --pedantic -Wall -Wextra, I get just the same warning about the implicit declaration.
Shouldn't c99 have declared that function implicitly as returning void? If it had, I would have expected a previous implicit declaration error similar to the one I got when I tried to redeclare it as returning float.
Is gcc broken here, or am I missing something in the standard?
You are reading the standard incorrectly. There's no such thing as implicit function declaration in C. It is removed from the language by C99.
GCC issues a warning when it sees an erroneous construct that looks like an implicit function declaration. This is OK as far as the standard is concerned. The standard requires a diagnostic here, and a warning is a diagnostic. You may use -Werror=implicit-function-declaration flag to GCC to turn this into an error.
This is covered in a note to 6.5.1 Primary expressions:
2 - An identifier is a primary expression, provided it has been declared as designating an
object (in which case it is an lvalue) or a function (in which case it is a function
designator). 79)
79) Thus, an undeclared identifier is a violation of the syntax.
A conforming implementation is required by 5.1.1.3 Diagnostics to produce a diagnostic message in response to the syntax violation of a function call expression involving an undeclared identifier as the expression denoting the called function. It is of course free to proceed to compile the program as if the identifier had been declared in the implicit-int C89 style.
The paragraph 6.5.2.2p5 must be read with reference to the constraint 6.5.2.2p1:
1 - The expression that denotes the called function shall have type pointer to function
returning void or returning an object type other than an array type.
So, if the "expression that denotes the called function" does not have type "pointer to function returning an object type", it must ipso facto (by the constraint 6.5.2.2p1) have type "pointer to function returning void", and it is this case which the "Otherwise" in 6.5.2.2p5 covers. That is, with my insertion in [square brackets]:
5 - If the expression that denotes the called function has type pointer to function returning an object type, the function call expression has the same type as that object type, and has the value determined as specified in 6.8.6.4. Otherwise, [i.e. if the expression that denotes the called function has type pointer to function returning void,] the function call has type void.
This is a case of special language being required for void as opposed to object types; is not a licence for the called function expression to be or contain an undeclared identifier.
In Microsoft Oslo SDK CTP 2008 (using Intellipad) the following code compiles fine:
module M {
type T {
Text : Text;
}
}
while compiling the below code leads to the error "M0197: 'Text' cannot be used in a Type context"
module M {
type T {
Text : Text;
Value : Text; // error
}
}
I do not see the difference between the examples, as in the first case Text is also used in a Type context.
UPDATE:
To add to the confusion, consider the following example, which also compiles fine:
module M {
type X;
type T {
X : X;
Y : X;
}
}
The M Language Specification states that:
Field declarations override lexical scoping to prevent the type of a declaration binding to the declaration itself. The ascribed type of a field declaration must not be the declaration itself; however, the declaration may be used in a constraint. Consider the following example:
type A;
type B {
A : A;
}
The lexically enclosing scope for the type ascription of the field declaration A is the entity declaration B. With no exception, the type ascription A would bind to the field declaration in a circular reference which is an error. The exception allows lexical lookup to skip the field declaration in this case.
It seems that user defined types and built-in (intrinsic) types are not treated equal.
UPDATE2:
Note that Value in the above example is not a reserved keyword. The same error results if you rename Value to Y.
Any ideas?
Regards, tamberg
From what I am seeing you have redefined Text:
Text : Text
and then you are attempting to use it for the type of Value:
Value : Text
which is not allowed. Why using a type name as a property redefines a type I'm not entirely clear on (still reading M language specification), but I'm sure there's a good reason for it. Just name Text something that's not already a defined type (escaping it with brackets ([Text]) does not work either).
http://social.msdn.microsoft.com/Forums/en-US/oslo/thread/fcaf10a1-52f9-4ab7-bef5-1ad9f9112948
Here's the problem: in M, you can do tricks like this:
module M
{
type Address;
type Person
{
Addresses : Address*;
FavoriteAddress : Address where value in Addresses;
}
}
In that example, "Addresses" refers to Person.Addresses. The problem, then, is that when you write something innocuous like
module M
{
type T
{
Text : Text;
SomethingElse : Text;
}
}
...then the "Text" in the type ascription for SomethingElse refers not to Language.Text, but to T.Text. And that's what's going wrong. The workaround is to write it like this:
module M
{
type T
{
Text : Text;
SomethingElse : Language.Text;
}
}
(You may wonder why things like "Text : Text" work in the example above. There's a special rule: identifiers in a field's type ascription cannot refer to the field itself. The canonical example for this is "Address : Address".)