Monday, April 22, 2019

Digest for comp.lang.c++@googlegroups.com - 23 updates in 5 topics

"Heinz Müller" <Heinz.Mueller69@gmail.com>: Apr 22 05:09PM +0200

#include <type_traits>
 
using namespace std;
 
template<typename T>
void f123( typename enable_if<is_unsigned<T>::value, T>::type t )
{
}
 
int main()
{
unsigned u;
int i;
 
f123( u );
f123( i ); // shoudn't work
}
 
Why dows the compiler not find at least the "valid" unsigned f123?
gazelle@shell.xmission.com (Kenny McCormack): Apr 22 03:13PM

In article <q9klf7$gah$1@news.albasani.net>,
> f123( i ); // shoudn't work
>}
 
>Why dows the compiler not find at least the "valid" unsigned f123?
 
Your program has undefined behavior, so anything is possible.
 
And, anything is right.
 
And, so on...
 
--
Religion is what keeps the poor from murdering the rich.
 
- Napoleon Bonaparte -
Manfred <noname@invalid.add>: Apr 22 06:34PM +0200

On 4/22/19 5:09 PM, Heinz Müller wrote:
>      f123( i ); // shoudn't work
> }
 
> Why dows the compiler not find at least the "valid" unsigned f123?
 
I'm not sure why, but typically enable_if is used either on template
arguments or on return value types.
It works if rewritten as follows:
 
 
#include <type_traits>
#include <iostream>
 
using namespace std;
 
template<typename T, typename =
typename enable_if<is_unsigned<T>::value, T>::type>
void f123( T t )
{
cout << "f123(" << t << ")" << endl;
}
 
int main()
{
unsigned u = 1;
int i = 2;
 
f123( u );
f123( i ); // shoudn't work
}
 
(I added the required initializers to get rid of UB)
Manfred <noname@invalid.add>: Apr 22 06:40PM +0200

On 4/22/19 6:34 PM, Manfred wrote:
>   f123( i ); // shoudn't work
> }
 
> (I added the required initializers to get rid of UB)
 
As said, also with return types:
 
#include <type_traits>
#include <iostream>
 
using namespace std;
 
template<typename T>
typename enable_if<is_unsigned<T>::value, void>::type f123( T t )
{
cout << "f123(" << t << ")" << endl;
}
 
int main()
{
unsigned u = 1;
int i = 2;
 
f123( u );
f123( i ); // shoudn't work
}
"Heinz Müller" <Heinz.Mueller69@gmail.com>: Apr 22 07:12PM +0200

> {
>   cout << "f123(" << t << ")" << endl;
> }
 
That seems more intuitive.
But what does the ", typename = ..." above mean?
----------
Manfred <noname@add.invalid>: Apr 22 10:40PM +0200

On 4/22/2019 7:12 PM, Heinz Müller wrote:
 
> That seems more intuitive.
> But what does the ", typename = ..." above mean?
>                      ----------
That is an unnamed template argument, with a default that is the result
of enable_if.
In the template it is a placeholder for a type argument that is not used
- in fact it is used only to trigger the evaluation of its default type,
which is the result of the enable_if expression.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 22 11:25PM +0200

On 22.04.2019 17:09, Heinz Müller wrote:
>      f123( i ); // shoudn't work
> }
 
> Why dows the compiler not find at least the "valid" unsigned f123?
 
Template argument deduction doesn't work on *dependent* types, like the
...::type for your formal argument.
 
From the compiler's point of view there could be any number of
specializations of `enable_if`, with `::type`s that didn't at all
resemble the `T` type. And these specialization could be defined in
indirect ways that involved much compile time activity to straighten
out. It would be unreasonable to require it to do that /in general/.
 
Template argument deduction is instead a more or less direct matching,
not considering any type indirection.
 
So, to do what you're trying to do, do
 
template<
class T,
class = enable_if_t< is_unsigned_v< T > >
 
void f123( const T value ) ...
 
Due to historical reasons, that template aliases were not available at
the time the `enable_if` appeared, the notation is full of annoying
ticks and warts like `_t` and `_v`.
 
I tend to reduce them via ¹simple aliases, e.g., off the cuff
 
template< bool condition > using Enable_if_ =
std::enable_if_t<condition>;
 
In some cases, such as `is_const_` and `is_base_and_derived_`, the
wrapper or alias also adds much needed generality or clarity.
 
 
Cheers!
 
- Alf
 
References:
¹ E.g. see <url:
https://github.com/alf-p-steinbach/cppx-core/blob/master/source/cppx-core/language/tmp/basic-type-traits.hpp>
Chris Sykes <chris@amtiskaw.net>: Apr 22 10:32AM +0100

On 21/04/2019 14:09, Bart wrote:
> the #include, it doesn't work (doesn't know 'std'); if I keep that
> but get rid of std::, it doesn't work either (doesn't know 'cout').
> And this is the simplest possible program.
 
Well in C++ you can always add:
 
using std::cout, std::string; // comma separated list allowed since c++17
 
To pull in precisely what you want to use from the standard library, or:
 
using std;
 
To dump everything into the local scope.
 
The biggest advantage (IMO) of C++ namespaces is that they provide a
mechanism to resolve otherwise ambiguous names; that is, even when
`using std;`, you can fully qualify references to string, cout
or whatever to resolve any ambiguity with symbols defined elsewhere.
 
Many other languages do something similar; the compiler (or interpreter)
raises an error (hopefully identifying where the conflicting symbols
are declared), and you fix it by qualifying the references with the
appropriate namespace, package, module/whatever prefix.
Chris Sykes <chris@amtiskaw.net>: Apr 22 10:43AM +0100

On 21/04/2019 13:37, Juha Nieminen wrote:
> undrestandability of code shouldn't be reliant on an IDE. The code
> should remain readable and understandable even if you are just looking
> at it with a vanilla text editor.
 
Absolutely. Time saved in code review (or just coming back to some
code *you* wrote a while ago) vastly outweighs a few characters
saved when first entering the code, and both IDEs and editors tend
to have pretty good auto-complete when entering code these days
anyway.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 22 03:37PM

On Thu, 2019-04-18, Fred.Zwarts wrote:
>>locally, and don't expect such a name to conflict with the standard
>>library. Not to mention names like find().
 
> I don't think it is wise to use such a widely used name as 'string' locally.
 
I do. Namespaces were added to C++ (at least partly) to allow that;
seems a waste not to take advantage of it.
 
How much of an advantage it is varies from person to person.
Personally I find prefixes quite distracting: I strongly prefer
e.g. "insert(a, b)" to "my_insert(a, b)".
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 22 04:07PM

>> people just hate namespace prefixes in C++, and go to great lengths
>> to avoid them and will rabidly defend this practice, and oppose their
>> use. No amoung of argumentation will convince them otherwise.
...
 
> Earth::wind, Earth::rock
 
> When I see 'wind', 'rock', how am I supposed to think with these words?
> Mars_wind, Earth_rock would be more clearer.
 
Just like Mars::wind and Earth::rock.
 
IMHO you're missing part of the point of namespaces. You're supposed
to /know/ when you're inside it, much like you're supposed to know
what planet you're on.
 
Or, if I had a brother called Donald, I'd call him "Donald" when
talking to my sister. I wouldn't call him "Donald Grahn" to make it
clear I'm not talking about Donald Duck, or Knuth. If I did, my
sister would be confused and possibly worried.
 
When you're not inside the namespace, using the full name is normally
the way to go: if a whole class or function only works on Earth::rock,
then that's a sign maybe it should have been in the Earth namespace.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
blt_7W@zimftew_1xvn.com: Apr 22 08:31AM

On Sun, 21 Apr 2019 13:34:25 +0200
>> const.
 
>/I/ am the person writing these functions here. /I/ know they are not
>simple arithmetic. The result of some of the functions is a single
 
You must have a magic compiler that can execute loops, call other functions and
execute other non arithmetic and boolean logic constructs at compile time then.
 
>integer, others result in arrays of data, but the functions involved are
>not simple. There are good reasons why I am using functions, not just
 
Give us an example of these complex functions that can still be reduced to
a single value at compile time.
David Brown <david.brown@hesbynett.no>: Apr 22 11:33AM +0200

>> simple arithmetic. The result of some of the functions is a single
 
> You must have a magic compiler that can execute loops, call other functions and
> execute other non arithmetic and boolean logic constructs at compile time then.
 
It's a C++14 compiler - there are several available. C++14 removed many
of the restrictions on C++11 constexpr functions.
 
<https://en.cppreference.com/w/cpp/language/constexpr>
 
>> not simple. There are good reasons why I am using functions, not just
 
> Give us an example of these complex functions that can still be reduced to
> a single value at compile time.
 
The code below is originally from C, rather than C++, simply augmented
by "constexpr". Even with optimisation disabled, a C++14 compiler must
calculate the CRC check here at compile time.
 
 
#include <stdint.h>
#include <string.h>
 
static constexpr const uint8_t crcTable8[256] = {
0x00, 0x8D, 0x97, 0x1A, 0xA3, 0x2E, 0x34, 0xB9,
0xCB, 0x46, 0x5C, 0xD1, 0x68, 0xE5, 0xFF, 0x72,
0x1B, 0x96, 0x8C, 0x01, 0xB8, 0x35, 0x2F, 0xA2,
0xD0, 0x5D, 0x47, 0xCA, 0x73, 0xFE, 0xE4, 0x69,
0x36, 0xBB, 0xA1, 0x2C, 0x95, 0x18, 0x02, 0x8F,
0xFD, 0x70, 0x6A, 0xE7, 0x5E, 0xD3, 0xC9, 0x44,
0x2D, 0xA0, 0xBA, 0x37, 0x8E, 0x03, 0x19, 0x94,
0xE6, 0x6B, 0x71, 0xFC, 0x45, 0xC8, 0xD2, 0x5F,
0x6C, 0xE1, 0xFB, 0x76, 0xCF, 0x42, 0x58, 0xD5,
0xA7, 0x2A, 0x30, 0xBD, 0x04, 0x89, 0x93, 0x1E,
0x77, 0xFA, 0xE0, 0x6D, 0xD4, 0x59, 0x43, 0xCE,
0xBC, 0x31, 0x2B, 0xA6, 0x1F, 0x92, 0x88, 0x05,
0x5A, 0xD7, 0xCD, 0x40, 0xF9, 0x74, 0x6E, 0xE3,
0x91, 0x1C, 0x06, 0x8B, 0x32, 0xBF, 0xA5, 0x28,
0x41, 0xCC, 0xD6, 0x5B, 0xE2, 0x6F, 0x75, 0xF8,
0x8A, 0x07, 0x1D, 0x90, 0x29, 0xA4, 0xBE, 0x33,
0xD8, 0x55, 0x4F, 0xC2, 0x7B, 0xF6, 0xEC, 0x61,
0x13, 0x9E, 0x84, 0x09, 0xB0, 0x3D, 0x27, 0xAA,
0xC3, 0x4E, 0x54, 0xD9, 0x60, 0xED, 0xF7, 0x7A,
0x08, 0x85, 0x9F, 0x12, 0xAB, 0x26, 0x3C, 0xB1,
0xEE, 0x63, 0x79, 0xF4, 0x4D, 0xC0, 0xDA, 0x57,
0x25, 0xA8, 0xB2, 0x3F, 0x86, 0x0B, 0x11, 0x9C,
0xF5, 0x78, 0x62, 0xEF, 0x56, 0xDB, 0xC1, 0x4C,
0x3E, 0xB3, 0xA9, 0x24, 0x9D, 0x10, 0x0A, 0x87,
0xB4, 0x39, 0x23, 0xAE, 0x17, 0x9A, 0x80, 0x0D,
0x7F, 0xF2, 0xE8, 0x65, 0xDC, 0x51, 0x4B, 0xC6,
0xAF, 0x22, 0x38, 0xB5, 0x0C, 0x81, 0x9B, 0x16,
0x64, 0xE9, 0xF3, 0x7E, 0xC7, 0x4A, 0x50, 0xDD,
0x82, 0x0F, 0x15, 0x98, 0x21, 0xAC, 0xB6, 0x3B,
0x49, 0xC4, 0xDE, 0x53, 0xEA, 0x67, 0x7D, 0xF0,
0x99, 0x14, 0x0E, 0x83, 0x3A, 0xB7, 0xAD, 0x20,
0x52, 0xDF, 0xC5, 0x48, 0xF1, 0x7C, 0x66, 0xEB
};
 
static constexpr uint8_t crcData8(uint8_t crc, const uint8_t* pData,
size_t size) {
while (size--) {
crc = crcTable8[crc ^ (*pData++)];
}
return crc;
}
 
uint8_t test(void) {
const uint8_t s[] = "Hello, world!";
constexpr uint8_t c = crcData8(0, s, sizeof(s));
return c;
}
blt_q7_a8fplu@0gkdzjla5uk04q8c.com: Apr 22 09:53AM

On Mon, 22 Apr 2019 11:33:48 +0200
 
>The code below is originally from C, rather than C++, simply augmented
>by "constexpr". Even with optimisation disabled, a C++14 compiler must
>calculate the CRC check here at compile time.
 
Or not even in 2017 mode....
 
fenris$ c++ -v
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
fenris$ c++ -std=c++17 test.cc
test.cc:49:24: error: constexpr variable 'c' must be initialized by a constant
expression
constexpr uint8_t c = crcData8(0, s, sizeof(s));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~
test.cc:42:40: note: read of non-constexpr variable 's' is not allowed in a
constant expression
crc = crcTable8[crc ^ (*pData++)];
^
test.cc:49:28: note: in call to 'crcData8(0, &s[1], 13)'
constexpr uint8_t c = crcData8(0, s, sizeof(s));
^
1 error generated.
 
Whoops.
Ian Collins <ian-news@hotmail.com>: Apr 22 10:05PM +1200

>> by "constexpr". Even with optimisation disabled, a C++14 compiler must
>> calculate the CRC check here at compile time.
 
> Or not even in 2017 mode....
 
It is if you fix the spello:
 
constexpr uint8_t s[] = "Hello, world!";
 
gcc is a bit lenient on the original.
 
--
Ian.
David Brown <david.brown@hesbynett.no>: Apr 22 12:14PM +0200

On 22/04/2019 12:05, Ian Collins wrote:
 
> It is if you fix the spello:
 
>      constexpr uint8_t s[] = "Hello, world!";
 
> gcc is a bit lenient on the original.
 
So it is - even in pedantic mode. I guess that could be filed as a bug.
 
(clang will, of course, do everything at compile time with "s" being
"const", as long as "c" is also changed to "const" instead of
"constexpr". But it then does so for optimisation, not because the
rules of C++ require it.)
blt_zwrtvhou@mlz0jr60in9.ac.uk: Apr 22 02:42PM

On Mon, 22 Apr 2019 22:05:32 +1200
 
>> Or not even in 2017 mode....
 
>It is if you fix the spello:
 
> constexpr uint8_t s[] = "Hello, world!";
 
Hmm, thats interesting. Guess I should have caught up with 2014 constexprs.
I can't help thinking that the compiler executing code at compile time could
be an interesting avenue for obscure bugs and compile time crashes.
David Brown <david.brown@hesbynett.no>: Apr 22 05:05PM +0200


> Hmm, thats interesting. Guess I should have caught up with 2014 constexprs.
> I can't help thinking that the compiler executing code at compile time could
> be an interesting avenue for obscure bugs and compile time crashes.
 
Obscure bugs, yes. Compile time crashes are just compile-time error
messages.
 
There are still restrictions on what you can do in constexpr functions,
of course. But they are a lot less than in C++11.
blt_2D6@zz6h0uww529.com: Apr 22 03:26PM

On Mon, 22 Apr 2019 17:05:27 +0200
>> be an interesting avenue for obscure bugs and compile time crashes.
 
>Obscure bugs, yes. Compile time crashes are just compile-time error
>messages.
 
No I was thinking of an actual compiler crash if its get stuck trying to solve
some version of the halting problem and blows up. A compiler is just a
program after all and a very complex one to boot so hidden bugs are almost
a certainty.
 
A good one in the past was feeding this to some old versions of the Solaris
compiler:
 
class myabstractclass
{
:
virtual void func() = 1;
:
};
 
Caused a fairly comprehensive compiler internal error dump.
Thiago Adams <thiago.adams@gmail.com>: Apr 22 05:08AM -0700

On Friday, April 19, 2019 at 11:40:57 AM UTC-3, Bonita Montero wrote:
> could increase the performance of string-handling significantly. On the
> other side, there are many standard-library facilities that only accept
> a basic_string so this type of string would be incompatible.
 
 
In C, I use my own version called "LocalStringBuilder"
http://thradams.com/localstrbuilder.htm
 
It uses a buffer in the stack but if necessary it allocates
memory on heap.
 
In C++ (maybe?) this can be done changing the allocator of std::string
or creating a new specialized template class.
James Kuyper <jameskuyper@alumni.caltech.edu>: Apr 22 09:02AM -0400

On 4/20/19 4:32 PM, Melzzzzz wrote:
>> "stacticized" strings like in C this wouldn't blow up the stack to its
>> maximum size.
 
> Arrays on stack is always bad idea.
 
Can you give a reason for that judgment that isn't addressed by choosing
a large stack size and allocating only small arrays on the stack (for
suitable values of "large" and "small")?
"Öö Tiib" <ootiib@hot.ee>: Apr 22 07:22AM -0700

On Friday, 19 April 2019 17:40:57 UTC+3, Bonita Montero wrote:
> could increase the performance of string-handling significantly. On the
> other side, there are many standard-library facilities that only accept
> a basic_string so this type of string would be incompatible.
 
Sure there are such classes. Fair amount of optimizations can be
done by using std::array or mundane array plus std::string_view.
That combo fits fully to stack. Alternatively (for fans of
compile-time processing) that combo can be fully constexpr.
When there is issue that even the length of string (and its buffer
needed) is uncertain compile-time then unfortunately there are
no standard solutions since neither VLA nor alloca() are in C++
(but one and/or other is usually supported as extension).
 
However first I always make unoptimized version (that just uses
std::strings) fully ready and covered with tests. Budget for
performance works is lot easier to get when there is something
that is worth to optimize. Otherwise such tinkering wastes too
lot of time first and makes C++ team to look sluggish compared
to Python or Java team.
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Apr 21 06:49PM -0700

On Friday, April 19, 2019 at 4:05:13 PM UTC-4, Mr Flibble wrote:
> And Satan invented fossils, yes?
 
You are citing arguments I've never made as though they were my
arguments, and using it to refute something that it not something
I believe or have ever taught.
 
If you want to know the truth ... learn it:
 
https://groups.google.com/d/msg/comp.lang.c/YLNsjdKKFR4/VapszCkrCwAJ
 
--
Rick C. Hodgin
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: