This question already has an answer here:
Elaborated-type-specifier for a scoped enum must not use the ‘class’ keyword
(1 answer)
Closed 5 years ago.
I have code that contains the line
enum struct cols: int8_t {red, blue, green};
When i compile this, i get errors:
test.cpp:4:1: warning: elaborated-type-specifier for a scoped enum must not use the 'struct' keyword
enum struct cols: int8_t {red, blue, green};
^
test.cpp:4:13: error: use of enum 'cols' without previous declaration
enum struct cols: int8_t {red, blue, green};
^
test.cpp:4:17: error: expected unqualified-id before ':' token
enum struct cols: int8_t {red, blue, green};
^
However if i put the line
#include <iostream>
at the top, it compiles without complaint.
Is there an explanation for this?
(I am using g++ 4.9.4, but this behaviour is also displayed with g++ 5.4.0.)
std::int8_t is not a built-in type. It is, like all other exact-width types, an optional typedef to a built-in type, present only if your system has an appropriate type of that width. This and other available std::[u]int*_t types are defined in <cstdint>. Therefore, you need to #include <cstdint>.
As my above paragraph indicates, you should also specify the std:: namespace qualifier, as stdlib symbols in the <c*> headers are not required to be made available in the global namespace.
Presumably <iostream> was previously indirectly including <cstdint> by some route, but you should not rely on that; you should #include the correct header for every library symbol you use.
Then the thing about struct is a red herring arising from the other, main problem of the unknown underlying type; see Elaborated-type-specifier for a scoped enum must not use the ‘class’ keyword, which now that I look at it, is nearly an exact duplicate of your question.
Related
I would like to use unique_ptr inside map in vector. But I got an error message.
I am not sure why and how to solve this problem.
This is the code.
#include <memory>
int main(int argc, char** argv)
{
std::vector<std::map<int, std::unique_ptr<std::string>>> outputContainers;
std::map<int, std::unique_ptr<std::string>> outputContainer;
outputContainer[0] = std::make_unique<std::string>("test");
outputContainers.push_back(std::move(outputContainer));
}
This is an error message.
Error C2280 'std::pair<const int,std::unique_ptr<std::string,std::default_delete<std::string>>>::pair(const std::pair<const int,std::unique_ptr<std::string,std::default_delete<std::string>>> &)': attempting to reference a deleted function test C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.24.28314\include\xmemory 671
When a vector needs to reallocate, it may move elements to the new storage if the element's type is_nothrow_move_constructible; otherwise, it has to copy (so it can unwind back to the original state if any constructor throws an exception).
std::map's move constructor is not required to be noexcept. Some implementations may provide stronger guarantees than required by the standard, and make it noexcept; others may not.
The interaction of these two facts leads to a vector of maps of move-only type being non-portable - it may compile with some implementations but not others.
uint32_t u32 = 0;
uint16_t u16[2];
static_assert(sizeof(u32) == sizeof(u16), "");
memcpy(u16, &u32, sizeof(u32)); // defined?
// if defined, how to we access the data from here on?
Is this defined behaviour? And, if so, what type of pointer may we use to access the target data after the memcpy?
Must we use uint16_t*, because that suitable for the declared type of u16?
Or must we use uint32_t*, because the type of the source data (the source data copied from by memcpy) is uint_32?
(Personally interested in C++11/C++14. But a discussion of related languages like C would be interesting also.)
Is this defined behavio[u]r?
Yes. memcpying into a pod is well-defined and you ensured that the sizing is the correct.
Must we use uint16_t*, because that suitable for the declared type of u16?
Yes, of course. u16 is an array of two uint16_ts so it must be accessed as such. Accessing it via a uint32_t* would be undefined behavior by the strict-aliasing rule.
It doesn't matter what the source type was. What matters is that you have an object of type uint16_t[2].
On the other hand, this:
uint32_t p;
new (&p) uint16_t(42);
std::cout << p;
is undefined behavior, because now there is an object of a different type whose lifetime has begin at &p and we're accessing it through the wrong type.
The C++ standard delegates to C standard:
The contents and meaning of the header <cstring> are the same as the C standard library header <string.h>.
The C standard specifies:
7.24.1/3 For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value).
So, to answer your question: Yes, the behaviour is defined.
Yes, uint16_t* is appropriate because uint16_t is the type of the object.
No, the type of the source doesn't matter.
C++ standard doesn't specify such thing as object without declared type or how it would behave. I interpret that to mean that the effective type is implementation defined for objects with no declared type.
Even in C, the source doesn't matter in this case. A more complete version of quote from C standard (draft, N1570) that you are concerned about, emphasis mine:
6.5/6 [...] If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. [...]
This rule doesn't apply, because objects in u16 do have a declared type
I'm writing a constrexpr function taking either a CArray T(&)(N), either a std::array.
I think I have to write 2 functions (if you know better I would be happy to know),
But I'm concerned about what I wrote with the std::array
constexpr float LinInterp01(const std::array<float, N>& inArray, float inX);
Is it correct when writing a constrexpr function to pass by const & or not?
I think it should be because at compile time the compiler would instanciate a copy and there is no notion of L Value, at compile time.
Could someone explain me this?
C++ standard section § 7.1.5 [dcl.constexpr]
The definition of a constexpr function shall satisfy the following constraints:
— it shall not be virtual (10.3);
— its return type shall be a literal type;
— each of its parameter types shall be a literal type;
And section § 3.9 [basic.types]
A type is a literal type if it is:
— void; or
— a scalar type; or
— a reference type; or
— an array of literal type; or
— a class type (Clause 9) that has all of the following properties:
— it has a trivial destructor,
— it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template
that is not a copy or move constructor, and
— all of its non-static data members and base classes are of non-volatile literal types.
So yes, you can pass parameters by reference to constexpr functions.
Now whether or not your function calls will actually be evaluated at compile time depends on the body and calls of LinInterp01.
I would like to use the boost::geometry::simplify method with OGRLineStrings.
While I am able to register the OGRPointvia the macro:
BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(OGRPoint, double, cs::cartesian, OGRPoint::getX, OGRPoint::getY, OGRPoint::setX, OGRPoint::setY)
I am currently not able to use the following code:
#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/geometries/register/linestring.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(OGRPoint, double, cs::cartesian, OGRPoint::getX, OGRPoint::getY, OGRPoint::setX, OGRPoint::setY)
BOOST_GEOMETRY_REGISTER_LINESTRING(OGRLineString)
void example()
{
OGRLineString test;
OGRLineString simplified;
boost::geometry::simplify(test, simplified, 0.5);
}
The Simplyfy method doens't compile and I get errors stating something about boost:mpl::eval_if_c which doesn't help me.
A Boost.Geometry linestring must fulfil the Boost.Range Concept. A std::vector would, for example, do. But an OGRLineString, out of the box,.
First, there should be an iterator defined, walking over the points the OGRLineString contains. Using OGRLineString::getPoint(...) this should basically be possible.
Second, if the iterator is implemented, which is probably the toughest part, OGRLineString should be adapted to Boost.Range, e.g. as described here.
If that is done, Boost.Geometry should recognize the OGRLineString as a linestring and can read it.
However, to write into an OGRLineString, an additional step should be done. It should be a "mutable range". Because that is not (yet) defined in Boost.Range, it is until now a geometry-only thing and can be implemented by specializing three classes in the boost::geometry::traits namespace (clear, push_back and resize).
I am forced to use a third party dongle access library that provides an include file 'sense4.h' with code as follows:
#if !defined _WINDOWS_
#define WINAPI
#define CONST const
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned int UINT;
typedef unsigned long ULONG;
typedef char CHAR;
typedef char TCHAR;
typedef void VOID;
...
#endif /* !defined _WINDOWS */
...
unsigned long WINAPI S4Startup(
VOID
);
unsigned long WINAPI S4Cleanup(
VOID
);
...
The problem is that g++ 4.6.1 complains about lines of code where typedefed VOID is used:
sense4.h:375:9: error: ‘<anonymous>’ has incomplete type
sense4.h:376:1: error: invalid use of ‘VOID {aka void}’
sense4.h:383:9: error: ‘<anonymous>’ has incomplete type
sense4.h:384:1: error: invalid use of ‘VOID {aka void}’
Is there anything I can do without changing the 'sense.h' include file to make my project compile with g++?
Update 1
I found out that the section 18 of C++ Standard Core Language Closed Issues, Revision 30 states:
If the parameter-declaration-clause is empty, the function takes no arguments. The parameter list (void) is equivalent to the empty parameter list.
Can a typedef to void be used instead of the type void in the parameter list?
Rationale: The IS is already clear that this is not allowed.
Quick summary: The code is not valid C++, though there's some lack of clarity about whether it should be. Using void rather than VOID, or just using empty parentheses, will avoid the error.
I think this is a bug in g++.
I thought this was a bug in g++. I'm now convinced that it isn't, though I argue that it would be better to make this a warning rather than a fatal error.
Normally in C++, a function with no parameters is declared with empty parentheses:
int foo();
As a concession to C compatibility, C++ also allows a C-style prototype, using void to indicate that the function has no parameters (since empty parentheses mean something else in C):
int bar(void);
g++'s interpretation seems to be that the void in this syntax here doesn't refer to the incomplete type void; rather, it treats it as a special syntax with a distinct use of the keyword.
I think you'll need to modify the header file to get g++ to accept it.
gcc accepts it as valid C, but that's not helpful if you need to #include it from a C++ source file -- unless you write a C wrapper and invoke it from your C++ code, which might be an acceptable workaround.
(Incidentally, I hate typedefs like that. What's the purpose of typedef void VOID;? Did the author think void was too confusing? I suspect it's for compatibility with very old C compilers that didn't support the void keyword, but the need for that is long past.)
Here's the relevant description from the latest draft of the ISO C++ 2011 standard (8.3.5 [dcl.fct]):
The parameter-declaration-clause determines the arguments that can
be specified, and their processing, when the function is called. [ ...
] If the parameter-declaration-clause is empty, the function takes
no arguments. The parameter list (void) is equivalent to the empty
parameter list. Except for this special case, void shall not be a
parameter type (though types derived from void, such as void*,
can).
This implies that the void keyword in int bar(void); does refer to the type void. Since a typedef name is a synonym for the named type, int bar(VOID); should be equally legal. It would make the most sense for a typedef name like VOID to be accepted in place of void, but the wording of the standard actually refers to the keyword void, not to the type.
The whole purpose of permitting (void) is C compatibility. Just to add to the confusion, the 1990 ISO C standard requires the void keyword; the 1999 and 2011 C standards changed the wording, allowing a typedef instead. The response to C++ Defect Report #577 confirms that the current wording requires the void keyword, and proposes a change that will permit a typedef -- but that change is not yet in any ISO C++ standard. It will probably appear in the first Technical Corrigendum for C++ 2011, whenever it's published.
Thanks to another.anon.coward for finding the existing gcc bug report. I've added an overly verbose comment suggesting that the code is valid and the error message should not be produced -- and a later comment conceding that the code is invalid, but that a warning would be more appropriate than a fatal error.
In the meantime, I suggest contacting the provider of this sense4.h header file. If they intended it to #included only from C code, there's no real problem with it (other than the IMHO poor style); otherwise, they might consider using #ifdef __cplusplus, declaring the functions with (void) in C and with () in C++. And you could go ahead and make that change yourself. Whether g++ should accept the code or not, with a few changes it would be valid C, valid C++, acceptable to both gcc and g++, and better style.
If you've read this far and you're still awake, I'm impressed.