Can structured binding be used to define a bunch of constants that would be usable in a constant expression (like a case in a switch) ? How ?
To the effect of :
const auto [ file_type, folder_tye, sym_type ] = 42u, 43u, 44u ;
It is currently not possible to make a structured binding usable in constant expressions due to some technicalities of how they are specified in the standard.
That seems to be intended to be corrected via P2686, which however is currently still open and tagged C++26 and so won't be in C++23.
With the change in the paper simply adding constexpr will be enough.
Related
Functional languages with pattern matching (sometimes?) have the possibility to ignore some bound values, but with C++17 structured bindings there seem to be no way to do that (std::ignore with structured bindings?). The advice is to use a dummy name, but then we'll get warnings about unused variables.
With the latest heads of both clang and gcc, this does the expected thing, which is nice and useful,
[[maybe_unused]] auto x =4 ; // fine, no warning
[[maybe_unused]] auto [a,dummyb,dummyc] = std::tuple<int,int,float>(1,1,1.0f);
but I would also have hoped this would work:
auto [g,[[maybe_unused]]dummyh,[[maybe_unused]]dymmyi] =
std::tuple<int,int,float>(1,1,1.0f);
is there a specific reason attributes can not be used here? (in the standard as well as technically). Neither gcc or clang accepts this.
Edit, collecting the support status: (thanks to godbolt/compiler explorer). It works as expected in (could be earlier also):
gcc 8.0 trunk (g++ 8.0.0 20171015 experimental)
clang 4.0.0
icc 18 (not tested, according to specs)
msvc 19.22 (probably earlier) (Fixed, according to bug report)
Try it out in godbolt at https://gcc.godbolt.org/z/H2duYd
In the structure bindings paper:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0144r2.pdf
they discuss their reasoning:
3.8 Should there be a way to explicitly ignore components?
The motivation would be to silence compiler warnings about unused names.
We think the answer should be “not yet.” This is not motivated by use
cases (silencing compiler warnings is a motivation, but it is not a
use case per se), and is best left until we can revisit this in the
context of a more general pattern matching proposal where this should
fall out as a special case.
Symmetry with std::tie would suggest using
something like a std::ignore:
tuple<T1,T2,T3> f();
auto [x, std::ignore, z] = f(); // NOT proposed: ignore second element
However, this feels awkward.
Anticipating pattern matching in the language
could suggest a wildcard like _ or *, but since we do not yet have
pattern matching it is premature to pick a syntax that we know will be
compatible. This is a pure extension that can wait to be considered
with pattern matching.
Although this does not explicitly address [[maybe_unused]], I assume the reasoning might be the same. Stopping compiler warnings is not a use-case.
As a resolution to CWG 2360, the working draft of the standard gained the following wording ([dcl.attr.unused]):
The attribute may be applied to the declaration of a class, a typedef-name, a variable (including a structured binding declaration), a non-static data member, a function, an enumeration, or an enumerator.
For an entity marked maybe_unused, implementations should not emit a warning that the entity or its structured bindings (if any) are used or unused. For a structured binding declaration not marked maybe_unused, implementations should not emit such a warning unless all of its structured bindings are unused.
Structured binding declarations were previously not explicitly mentioned.
I have two enum class types: Type and SocketType. The following code won't compile and fails with the message mentioned in the question, in VC++ 2017:
static constexpr std::map<Type,SocketType> PacketTypeMap =
{
{Type::JUSTJOINED, SocketType::TCP},
{Type::CHAT_MESSAGE, SocketType::TCP},
{Type::REQUEST_WORLD, SocketType::TCP},
{Type::DATA_WORLD, SocketType::TCP},
{Type::DATA_PLAYER, SocketType::UDP},
{Type::RESPAWN_PLAYER, SocketType::TCP}
};
Been trying some variations and nothing works, but I'm sure I'm just missing something simple with the syntax.
std::map is not compatible with constexpr. There exists an experimental(?) library called frozen, which provides a constexpr-compatible frozen::map (besides frozen::unordered_map, frozen::string, and others).
However, most probably you just want to pick a simpler solution (e.g., a switch statement in a constexpr function).
Migrating the answer from the comments section into the answer section.
There are no constexpr maps. It uses dynamic allocation, which is not possible with constexpr. Get rid of constexpr, or use a different container for compile-type map.
Problem:
I am using VC++2010, so except a few supported features like decltype pre-C++11 is required.
Given a C++ identifier, is it possible to use some meta-programming techniques to check if that identifier is a type name or variable name. In order words, given the code below :
void f() {
s=(uint32)-1;
}
is it possible to somehow identify if uint32 is:
the name of a variable which means the RHS of the assignment is a subtraction;or
a type name where the RHS operand is literal -1 typecasted to (uint32)
by something like mytemplate<uint32> or similiar?
Rationale: I am using my own in-house developed mini parser to analyze/instrument C++ source code. But my mini parser lacks many features like building a table of identifier types so it always interpret the above code as either subtraction or typecast. My parser is able to modify the source code so that I can insert/modify anything surrounding the uint32 e.g.
void f() {
s=(mytemplate<uint32>(...))-1;
s=myfunc(uint32)-1;
}
But my inserted code will cause syntax error depending on the meaning of the identifier uint32 (type name Vs variable name). I am looking for some generic code that I can insert to cater for both cases.
I have the following:
typedef enum
{
FLS_PROG_SUCCESS,
FLS_PROG_FAIL,
FLS_ERASE_SUCCESS2U,
FLS_ERASE_FAIL,
FLS_READ_SUCCESS,
FLS_READ_FAIL,
FLS_FORMAT_SUCCESS,
FLS_FORMAT_FAIL
}FLS_JobResult_t;
void Foo(void)
{
FLS_JobResult_t ProgramStatus;
/* Then I try to initialize the variable value */
ProgramStatus = FLS_PROG_SUCCESS;
...
}
Innocent uh, but when compiling MISRA C gives the error:
The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category
And I found out that I shall write the initialization as follows:
ProgramStatus = (FLS_JobResult_t)FLS_PROG_SUCCESS;
And this just doesn't look good to me, it's like MISRA wants me to throw casts in all the code and that's too much.
Do you know why is this? I don't think this should be an issue but I've tried everything that comes to my mind and this was the only way of getting rid of this error, but it simply does not make any sense, does it?
Regards.
(Hi, this is a new account so I cannot use the comments section yet to ask for further clarification, so, my answer may be broader than needed)
Based on the text of the warning message I assume you are talking about MISRA-C:2012 (the latest standard) which is a great improvement over the prior ones in that much more effort in stating the rationale along with many more compliant and non-compliant examples have been added. This being Rule 10.3, the rationale is: since C permits assignments between different arithmetic types to be performed automatically, the use of these implicit conversions can lead to unintended results, with the potential for loss of value, sign or precision.
Thus MISRA-C:2012 requires the use of stronger typing, as enforced by its essential type model, which reduces the likelihood of these problems occurring.
Unfortunately many tools have not properly implemented the rules and the type model. In this case, your tool is incorrect, this is not a violation of essential type rules because ProgramStatus and FLS_PROG_SUCCESS are both the same essential type. In fact a similar example is shown in the standard itself, under the rule’s list of compliant examples:
enum enuma { A1, A2, A3 } ena;
ena = A1;
If your tool vendor disagrees you can post your question on the "official" MISRA forum to get the official answer and forward that to the vendor.
After some search for a way to check endianess at compile-time I've come up with the following solution:
static const int a{1};
constexpr bool is_big_endian()
{
return *((char*)&(a)) == 1;
}
GCC accepts this code only in some contexts where constexpr is required:
int b[is_big_endian() ? 12 : 25]; //works
std::array<int, testendian() ? 12 : 25> c; //fails
For the second case, GCC says error: accessing value of ‘a’ through a ‘char’ glvalue in a constant expression. I couldn't find anything in the standard that forbids such thing. Maybe someone could clarify in which case GCC is correct?
This is what I get from Clang 3.1 ToT:
error: constexpr function never produces a constant expression
§5.19 [expr.const]
p1 Certain contexts require expressions that satisfy additional requirements as detailed in this sub-clause; other contexts have different semantics depending on whether or not an expression satisfies these requirements. Expressions that satisfy these requirements are called constant expressions.
p2 A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression:
[...]
a reinterpret_cast (5.2.10);
So, (char*)&(a) evaluates to a reinterpret_cast, as such the function is never a valid constexpr function.
You should look into Boost.Detail.Endian
It is a mapping of several architectures to their endianness (through the macros BOOST_BIG_ENDIAN, BOOST_LITTLE_ENDIAN, and BOOST_PDP_ENDIAN). As far as I know, there is no actual way to determine the endianness at compile time, other than a list like this.
For an example implementation that uses Boost.Detail.Endian, you can see the library I'm hoping to get reviewed for submission to Boost: https://bitbucket.org/davidstone/endian/ (the relevant file is byte_order.hpp, but unsigned.hpp is necessary as well if you want to just use my implementation).
If N3620 - Network Byte Order Conversion is implemented, you'll be able to use the constexpr ntoh to check for endianness, but remember there are rare architectures like middle-endian and you'll never be able to support all of them.