Does the c++11 standard say anything about templated unions? (I can't find anything in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf, but I haven't read it that carefully.)
I have
template<typename T>
union u {
T a;
char b;
};
template<typename T>
u<T> make_u(T t) {
return { .a = t };
}
int main() {
return make_u<int>(1).a;
}
This code causes icpc -std=c++11 to say error: a designator into a template-dependent type is not allowed, g++ -std=c++0x to say error: expected primary-expression before ‘.’ token, and g++ -std=c++11 (version 4.8.0 (experimental)) to say internal compiler error: in lookup_field_1, at cp/search.c:387. I can get around this by replacing { .a = t } with t. However, I could not do this for fields which are not the first member of the union. Is there a way to pick some member other than the first one in a templated union, where the relevant member is template-dependent? (I could, of course, declare a union on the stack, and set the member equal to the value I want. But I could not do this in an initializer list or in a constexpr function.)
The { .a = t } syntax is a non-standard GNU extension, so its interaction with other C++ features is outside the scope of the C++ standard.
Solution: write standard C++:
u<T> make_u(T t) {
u<T> r;
r.a = t;
return r;
}
EDIT: AFAIK, in C++11, you can give your union a constructor (a constexpr if you like) that does the initialization you need. Example: http://ideone.com/s4GHjU
Related
I have the following code:
class MyClass
{
static constexpr bool foo() { return true; }
void bar() noexcept(foo()) { }
};
I would expect that since foo() is a static constexpr function, and since it's defined before bar is declared, this would be perfectly acceptable.
However, g++ gives me the following error:
error: ‘static constexpr bool MyClass::foo()’ called in a constant expression
This is...less than helpful, since the ability to call a function in a constant expression is the entire point of constexpr.
clang++ is a little more helpful. In addition to an error message stating that the argument to noexcept must be a constant expression, it says:
note: undefined function 'foo' cannot be used in a constant expression
note: declared here
static constexpr bool foo() { return true; }
^
So...is this a two-pass-compilation problem? Is the issue that the compiler is attempting to declare all the member functions in the class before any of them are defined? (Note that outside of the context of a class, neither compiler throws an error.) This surprises me; intuitively, I don't see any reason for static constexpr member functions not to be useable in any and all constant expressions, inside the class or out.
As T.C. demonstrated with some links in a comment, the standard is not quite clear on this; a similar problem arises with trailing return types using decltype(memberfunction()).
The central problem is that class members are generally not considered to be declared until after the class in which they're declared is complete. Thus, regardless of the fact that foo is static constexpr and its declaration precedes that of bar, it cannot be considered "available" for use in a constant expression until MyClass is complete.
As pointed out by Shafik Yaghmour, there is some attempt within the standard to avoid a dependency on the ordering of members within a class, and obviously allowing the example in the original question to compile would introduce an ordering dependency (since foo would need to be declared before bar). However, there is already a minor dependency on ordering, because although constexpr functions can't be called inside noexcept, a noexcept expression itself might depend on an earlier declaration inside the class:
class MyClass
{
// void bar() noexcept(noexcept(foo())); // ERROR if declared here
static constexpr bool foo();
void bar() noexcept(noexcept(foo())); // NO ERROR
}
(Note that this is not actually a violation of 3.3.7, since there is still only one correct program that is possible here.)
This behavior may actually be a violation of the standard; T.C. points out (in a comment below) that foo here should actually be looked up in the scope of the whole class. Both g++ 4.9.2 and clang++ 3.5.1 fail with an error when bar is declared first but compile with no errors or warnings when foo is declared first. EDIT: clang++ trunk-revision 238946 (from shortly before the release of 3.7.0) does not fail when bar is declared first; g++ 5.1 still fails.
Intriguingly, the following variation causes a "different exception specifier" with clang++ but not with g++:
class MyClass
{
static constexpr bool foo2();
void bar2() noexcept(noexcept(foo2()));
};
constexpr bool MyClass::foo2() { return true; }
void MyClass::bar2() noexcept(noexcept(MyClass::foo2())) { }
According to the error, the noexcept specification for the declaration of bar2 evaluates to noexcept(false), which is then considered a mismatch for noexcept(noexcept(MyClasss::foo2())).
I am porting legacy C++ code to work with GCC 9.2. Using C++20 and GNU extensions are valid options.
The legacy code makes heavy use of anonymous structs nested in unions and aggregate initialization with designated initializes for example:
union u
{
int a;
struct
{
int b;
int c;
};
};
u f = { .b = 1, .c = 2 };
This example does compile with clang -std=gnu++2a -Wall -Wextra, but it does not compile with g++ -std=gnu++2a -Wall -Wextra:
error: too many initializers for 'u'
As there are many cases where such constructs are applied in the code, it would be necessary to apply potential changes to the code in an automated way (for example with the help of regular expressions). How can I compile "this code" with GCC 9.2 by changing the code in an automated way and as little as possible?
By moving the nested structure to the first position within the union and initializing the structure like an non-anonymous structure compiles with g++ -std=gnu++2a -Wall -Wextra:
union u {
struct
{
int b;
int c;
};
int a;
};
u f = { {.b = 1, .c = 2 } };
It should be possible to detect all anonymous structs within unions with regular expressions in the union's definitions. But I do not see how regular expressions can be used to modify the list initialization appropriately.
You can initialize only one member of the union:
because of 15.6.2 [class.base.init] paragraph 8:
An attempt to initialize more than one non-static data member of a union renders the program ill-formed.
so if you put: { .b=1, .c=2 } it sees you are initializing two members.
Then you can initialize either, .b or .c but not both.
Moreover:
If the element is an anonymous union object and the initializer list is a designated-initializer-list, the anonymous union object is initialized by the designated-initializer-list{D}, where D is the designated-initializer-clause naming a member of the anonymous union object. There shall be only one such designated-initializer-clause.
The key is: where D is the designated-initializer-clause naming a member of the anonymous union object
You may get more info here.
To be able to give a value to the members of the struct you should give an element:
union u
{
int a;
struct
{
int b;
int c;
} v; // <-- this
};
u f = { .v = { .b = 1, .c = 2 } };
But this would break the accesses to every u: i.e. f.v.b = 0.
So I think your construct is not compatible with C++20. Why clang compiles and works? May be it is an extension when there are no constructors and/or destructors involved.
Given the example code:
struct S {
char data[5];
int a;
};
When running the "Run code analysis" in Microsoft Visual Studio, It warns to initialize all variables.
Now I know you can do this a number of ways, create a default constructor such as:
S() :
data{0},
a{0} {
}
That makes the warning go away. But what if you don't want to manually create the default constructor.
something like:
struct S {
char data[5];
int a = 0;
};
gets rid of the warning for a but not data, though you can fix that by adding {} after like so: char data[5]{}; this seems to make the code analysis happy.
That got me thinking, you can also initialize a like int a{0};
So my question is, are these all valid, and which is preferred?
Side note: I noticed std::array has _Ty _Elems[_Size]; which it never initializes anywhere, nor does it have {} after it, I'm assuming they just ignore this warning? Or are they doing something I'm not noticing to "fix" the warning?
Also wanted to add that this code:
#include
#include
template<class T, std::size_t N>
struct static_vector {
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N] = {0};
T& operator[](std::size_t pos) {
return *std::launder(reinterpret_cast<T*>(&data[pos]));
}
};
int main(int argc, char**) {
static_vector<int, 10> s;
s[0] = argc;
return s[0];
}
under gcc9.1 -std=c++17 -Wall produces no warnings,
yet the same code under clang8.0 -std=c++17 -Wall gives me:
warning: suggest braces around initialization of subobject [-Wmissing-braces]
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N] = {0};
^
{}
I see that I can set it to = {}; which fixes it, just wondering why one compiler would produce a warning when the other doesn't? Which one is to spec?
The guideline from CPPCoreGuidelines on this states: Don’t define a default constructor that only initializes data members; use in-class member initializers instead
So you can just do:
struct S {
char data[5] = {0};
int a = 0;
};
As to your other question about the lack of warning related to std::array, GCC has a note which states:
Warnings from system headers are normally suppressed, on the assumption that they usually do not indicate real problems and would only make the compiler output harder to read.
I believe this would be true of MSVC as well.
In C++ for each declarator, the initializer may be one of the following:
1. ( expression-list )
2. = expression
3. { initializer-list }
The description for these are as follows:
comma-separated list of arbitrary expressions and braced-init-lists in parentheses
the equals sign followed by an expression
braced-init-list: possibly empty, comma-separated list of expressions and other braced-init-lists
Well which type of initialization to prefer actually depends upon context. To initialize data members in a class I personally prefer in class initialization using braced initializer, as in that case we don't have to write a user defined default constructor, compiler generated one is always efficient.
Class members
Non-static data members can be initialized with member initializer
list or with a default member initializer.
In your case you can probably use:
struct S {
char data[5] = {0}; //initialize by zero
int a = 0;
};
or to give them different values also:
struct S {
char data[5] = {0,1,2,3,4};
int a = 0;
};
For more info see Initialization
struct A {
int a = 0;
constexpr A() { a = 1; }
};
constexpr bool f() {
constexpr A a;
static_assert(a.a == 1, ""); // L1: OK
return a.a == 1;
}
static_assert(f(), ""); // L2: Error, can not modify A::a in constexpr
Online Compiler URL: http://goo.gl/jni6Em
Compiler: clang 3.4 (with -std=c++1y)
System: Linux 3.2
If I delete L2, this code compiles. If I add L2, the compiler complained "modification of object of const-qualified type 'const int' is not allowed in a constant expression". I am not a language lawyer, so I am not sure whether this is true. However, if it is, why compiler didn't complain anything about L1, since it also called A() as constexpr? Is this a bug of clang? Or did I miss anything?
Reference: http://en.cppreference.com/w/cpp/language/constexpr
BTW, if I change "constexpr A a;" to "A a;" (remove constexpr keyword), L1 failed to compile which is expect. However, the compiler didn't complain about L2 anymore.
Online Compiler URL about this: http://goo.gl/AoTzYx
I believe this is just a case of compilers not having caught up to the changes proposed for C++14. Your constexpr constructor satisfies all the conditions listed in §7.1.5/4 of N3936. Both gcc and clang fail to compile your code, but for different reasons.
clang complains:
note: modification of object of const-qualified type 'const int' is not allowed in a constant expression
which doesn't make much sense, but reminds me of the C++11 restriction that constexpr member functions are implicitly const (this is a constructor, and that doesn't apply, but the error message is reminiscent of that). This restriction was also lifted for C++14.
gcc's error message is:
error: constexpr constructor does not have empty body
Seems pretty clear that gcc still implements the C++11 rules for constexpr constructors.
Moreover, N3597 lists this example:
struct override_raii {
constexpr override_raii(int &a, int v) : a(a), old(a) {
a = v;
}
constexpr ~override_raii() {
a = old;
}
int &a, old;
};
N3597 was superseded by N3652, which contains the wording found in the current draft. Unfortunately, the earlier example disappears, but, again, nothing in the current wording says you cannot assign values to data members within the body of a constexpr constructor.
Update (2017-10-03)
clang fixed this, but there has been no new release yet: https://bugs.llvm.org/show_bug.cgi?id=19741
(Compiler explorer)
Consider the following code:
template <typename T>
class B
{
};
template <typename T>
B<T> f(T& t)
{
return B<T>();
}
class A
{
class C {};
C c;
public:
A() {}
decltype(f(c)) get_c() const { return f(c); }
};
int main()
{
A a;
a.get_c();
}
When I try to compile this, I get the error:
test.cpp: In member function 'B<A::C> A::get_c() const':
test.cpp:31:46: error: conversion from 'B<const A::C>' to non-scalar type 'B<A::C>' requested
It seems that in the decltype, the compiler doesn't know that this is a const member function and therefore c is of type const C, and as a result incorrectly deduces the type of f(c) to be B<C> rather than B<const C> which is what it really is.
Am I doing something incorrectly, or is this a compiler bug? I use gcc 4.6, but 4.4 and 4.5 exhibit the same behaviour.
The compiler operates correctly according to the current C++0x WP. See this issue report, which is currently being worked on.
Possibly the final C++0x Standard won't change the meaning of your decltype application in the return type before the function name. You would need to move it to after the parameter list using -> decltype(f(c)), which hopefully will do The Right thing in final C++0x.
No, decltype is not supposed to take into account whether the function is const or not, because it can't. The same could have been written differently:
typedef decltype(f(c)) return_type;
return_type get_c() const { return f(c); }
Correction: decltype(f(c)) shouldn't even compile, because c is not static.
f needs to take an rvalue reference, not an lvalue reference.
I don't think you're allowed to use decltype on anything you wouldn't normally be able to call. I haven't been able to find anything in the standard that would allow you to access c, even within a decltype expression, outside of anywhere you could use c. Since you don't have a this pointer at the point you're trying to do your thing, I don't think you can do what you're trying to do. Doing so doesn't work in MSVC 2010 at least, and it has nothing to do with const.
I considered using declval to get one but you can't access A&&.c because A is an incomplete type at that point. I can't see anyway to do what you're trying to do other than something like so:
decltype(f(declval<C const>())) get_c() const { ... }