Thursday, January 21, 2016

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

Dmitry Chichkov <dchichkov@gmail.com>: Jan 21 10:57AM -0800

There is a trick with 'inline namespace' that seems to allow static function overriding in C/C++. Which in turn allows organizing cross-platform code in a nice way.
 
I'm trying to get feedback on potential pitfalls of that technique. Here is a Git wiki page that describes it: https://github.com/dchichkov/curious-namespace-trick/wiki/Curious-Namespace-Trick
 
Briefly, it goes along these lines - if the code below would be compiled with -Dplatform=arm, the C function dot() in the common code would call platform specific add(). If platform specific add() is not available, common one will be called. If the code is built with -Dplatform=common the common version of add() will be called.
 
 
// output:
// dmitry@t:~$ g++ func.cpp -Dplatform=common ; ./a.out
// common add
// dmitry@t:~$ g++ func.cpp -Dplatform=arm ; ./a.out
// arm add
#include <stdio.h>
 
namespace project {
// arm/math.h
namespace arm {
inline void add_() {printf("arm add\n");} // try comment out
}
 
// math.h
inline void add_() {
//
printf("common add\n");
//
} inline namespace platform {inline void add() {add_();}}
 
 
inline void dot_() {
//
add();
//
} inline namespace platform {inline void dot() {dot_();}}
}
 
int main() {
project::dot();
return 1;
}
 
 
This technique seems to be an alternative to weak linking, CRTP, traits, etc. and it works for functions, template functions and in C++-11 for template types. It be great to get some feed-back from C/C++ gurus on potential problems with this approach and better alternatives.
 
 
-- Dmitry Chichkov
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jan 21 08:39PM +0100

On 1/21/2016 7:57 PM, Dmitry Chichkov wrote:
> C++-11 for template types. It be great to get some feed-back from
> C/C++ gurus on potential problems with this approach and better
> alternatives.
 
Code that's specific to a given platform typically needs headers for
that platform. And these headers are typically not available when the
code is compiled on another platform. This means that some selection of
which code to compile is needed anyway, and I would think that then the
above technique becomes just an added complication, redundant.
 
As I understand it inline namespaces (I haven't used them) were designed
to support versioning for template code, where client code may need to
specialize templates in their apparent original namespaces.
 
Three main ways of selecting which code to compile:
 
• conditional code blocks via `#if` and family,
 
• selection of headers via the compiler's include path, and
 
• creating a platform (or whatever-) specific code bundle by a tool that
picks that platform's files.
 
In addition it's technically possible to select headers via macro-based
include directives, but I tried that once and it quickly became a real
mess, running up against compiler and compiler version differences and
non-standard functionality.
 
Anyway, instead of using a macro to redefine a word like lowercase
"platform" that can easily be used for other purposes somewhere, I'd use
more obviously macro macros, with ugly all uppercase names, to let the
compiler see just one "inline". But then we're into selecting which code
to compile again. Which seems to make this redundant.
 
 
Cheers & hth.,
 
- Alf
Dmitry Chichkov <dchichkov@gmail.com>: Jan 21 03:23PM -0800

Hi Alf,
 
Yes, it is still necessary to select the correct platform-specific headers. And the tool like cmake, omake, etc would be the standard way of doing it. The problem is, after you've included a platform-specific definition - for example arm/math.h, you have duplicate function/type/template definitions in the common code (for example math.h) and in the platform-specific code.
 
This can be solved, if you'd simply implement the whole set of function in every platform-specific file, redirecting every unimplemented call to common routine. But if the number of supported platforms is large, this adds a lot of code/maintenance. There are ways to address that with preprocessor or templates, but it either forces one to mangle function names or it supports C++ only and requires to template every function/type, etc. It seems like this inline namespace trick gives cleaner alternative, but I haven't seen it in practice, and I'm not sure what are the potential pitfalls...
 
Cheers,
Dmitry
 
 
 
On Thursday, January 21, 2016 at 11:39:38 AM UTC-8, Alf P. Steinbach wrote:
David Brown <david.brown@hesbynett.no>: Jan 21 08:54AM +0100

On 20/01/16 23:37, Richard wrote:
 
>> https://en.wikipedia.org/wiki/GNU_Readline#Choice_of_the_GPL_as_GNU_Readline.27s_license
 
>> Sorry, I meant a citation for "RMS hates the LGPL".
 
> It's my opinion. I cite my own brain.
 
My brain seconds your opinion. Basically, RMS dislikes the LGPL because
it makes it easier for other people to release code that is not free
(meaning his definition of "free as in speech, not free as in beer").
If a library is released under the LGPL, it lets people use it with
closed source (with dynamic linking or by releasing linkable object
files). If a library is released under the GPL, people have to use the
GPL throughout code that uses it. (It does not seem to have occurred to
RMS that people will often simply not use that library, and find
alternatives. People choose the licence for their source code for many
reasons - it is rare that the licence required by one specific library
is the overriding concern.)
 
But perhaps it is too strong to say that RMS /hates/ the LGPL - he
merely sees it as a poor choice and compromise, and wants people to use
the full GPL whenever possible.
"Öö Tiib" <ootiib@hot.ee>: Jan 21 08:00AM -0800

On Thursday, 21 January 2016 09:54:56 UTC+2, David Brown wrote:
 
> But perhaps it is too strong to say that RMS /hates/ the LGPL - he
> merely sees it as a poor choice and compromise, and wants people to use
> the full GPL whenever possible.
 
LGPL was written by Richard Stallman himself to provide compromise
between GPL and permissive BSD/MIT. It may be that he hates making
compromises ... who knows.
"Öö Tiib" <ootiib@hot.ee>: Jan 21 08:07AM -0800

On Wednesday, 20 January 2016 23:10:40 UTC+2, Jorgen Grahn wrote:
 
> I don't think you need to look for a conspiracy. We all used 8-bit
> character sets back in the 1990s, and all the APIs looked like that,
> always had.
 
Back in the 1980s file systems often used RADIX-50 for file names.
IOW not 8-bit but there was 3 characters in 16 bits. The roots of
case-insensitivity of Windows are likely in it.
Vir Campestris <vir.campestris@invalid.invalid>: Jan 21 09:18PM

On 20/01/2016 21:10, Jorgen Grahn wrote:
> What is an STL file -- do you mean e.g. a std::fstream, or a FILE*?
 
FILE* isn't STL, it's plain old C.
 
> I don't think you need to look for a conspiracy. We all used 8-bit
> character sets back in the 1990s, and all the APIs looked like that,
> always had.
 
Ah yes, I remember when we had to cope with EBCDIC. And then there were
the ICL 1900s, with 6 bit bytes... yes, filenames were so consistent
back then.
 
Also 1993 saw the release of Windows NT, with wide character APIs -
before, IIRC, there were any Unicode characters past 64k. Some of us
were using it.
 
Andy
Robert Wessel <robertwessel2@yahoo.com>: Jan 21 04:02PM -0600

On Thu, 21 Jan 2016 08:07:47 -0800 (PST), 嘱 Tiib <ootiib@hot.ee>
wrote:
 
 
>Back in the 1980s file systems often used RADIX-50 for file names.
>IOW not 8-bit but there was 3 characters in 16 bits. The roots of
>case-insensitivity of Windows are likely in it.
 
 
There were some OSs that used interesting packing schemes, especially
for file name extensions, but three radix-50 characters don't fit in
16 bits. The limit would be three radix-40 characters, or a mixed
representation that had restrictions on character combinations.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Jan 21 10:48PM

On Thu, 2016-01-21, Vir Campestris wrote:
> On 20/01/2016 21:10, Jorgen Grahn wrote:
>> What is an STL file -- do you mean e.g. a std::fstream, or a FILE*?
 
> FILE* isn't STL, it's plain old C.
 
But std::fstream isn't STL either, so I still don't know what you
mean.
 
 
> Ah yes, I remember when we had to cope with EBCDIC. And then there were
> the ICL 1900s, with 6 bit bytes... yes, filenames were so consistent
> back then.
 
Did any of them have C++ implementations which anyone cared about? Of
course I'm not saying /everyone/ used APIs where a const char* was a
reasonable way to represent a file name, but it was very widely spread
and obviously there was enough of a mapping to support C++ on top of
it, for machines where anyone was interested.
 
My point is, it's not just Linux bias. At the time I used AmigaDOS
and believed iso8859-1 was the way of the future (and to hell with
anyone who thought they needed more).
 
> Also 1993 saw the release of Windows NT, with wide character APIs -
> before, IIRC, there were any Unicode characters past 64k. Some of us
> were using it.
 
I'm not claiming you didn't. Even I used Windows NT 4.0 in the late
1990s, although not with wide characters. Perhaps the C++ community
just ignored the problem until utf-8 came along and made it a non-
issue for a lot of people? After all, that's what I did myself.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Daniel <danielaparker@gmail.com>: Jan 20 03:44PM -0800

On Tuesday, January 19, 2016 at 11:29:36 PM UTC-5, Daniel wrote:
> > segmented_array.
 
> > https://github.com/FlibbleMr/neolib
 
> Thanks for posting this.
 
Two other comments.
 
First, you have a lot of occurrences of allocate followed by construct. I think you should wrap construct in a try/catch, or use an RAI artifice, to ensure that deallocate is called if construct throws.
 
Second, you call construct and destroy directly on the allocator. In C++ 11, these calls should go through std::allocator_traits, as allocators are not required to provide construct and destroy.
 
Daniel
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jan 21 07:09PM

On 20/01/2016 23:44, Daniel wrote:
 
> Two other comments.
 
> First, you have a lot of occurrences of allocate followed by construct. I think you should wrap construct in a try/catch, or use an RAI artifice, to ensure that deallocate is called if construct throws.
 
> Second, you call construct and destroy directly on the allocator. In C++ 11, these calls should go through std::allocator_traits, as allocators are not required to provide construct and destroy.
 
Fixed. Thanks for the feedback! :D
 
/Flibble
Yang Luo <youngluoyang@gmail.com>: Jan 21 01:14AM -0800

This is a example
SHELLEXECUTEINFO sei={0};//
sei.cbSize=sizeof(SHELLEXECUTEINFO);
sei.fMask=SEE_MASK_NOCLOSEPROCESS;
sei.hwnd=NULL;
sei.lpVerb=NULL;//_T("open");//_T("runas")
sei.lpFile=_T("cmd.exe");
sei.lpParameters=strParameters;
sei.lpDirectory =NULL;//_T("D:")
sei.nShow=SW_HIDE;
sei.hInstApp=NULL;
if(!ShellExecuteEx(&sei)){
DWORD dwStatus = GetLastError();
if(dwStatus == ERROR_CANCELLED)AfxMessageBox(_T("提升权限被用户拒绝"));
else if(dwStatus == ERROR_FILE_NOT_FOUND)AfxMessageBox(_T("所要执行文件没有找到"));
}
WaitForSingleObject(sei.hProcess,INFINITE);
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jan 21 01:43AM +0100

Finally a version that provides Unicode i/o via the standard streams, in
Windows, and works with both g++ and Visual C++.
 
The code below is an overview of how I configure the streams, in 5 more
or less intricate steps. I think no beginner can be expected to
implement this on their own. Especially not for a first little
personalized greeting program where his/her name should be presented.
 
So, I think it's way past time that someone provides basic i/o as a
library. After all most every other language has working basic i/o...
 
---------------------------------------------------------------------
File on GitHub:
https://github.com/alf-p-steinbach/cppx/blob/955b7b85733287934969fc7fc0add5fa011474bf/basics/io/stdstreams/iostreams_config.hpp
 
<code>
#pragma once
// p/cppx/basics/io/stdstreams/iostreams_config.hpp
// Copyright © Alf P. Steinbach 2015. Boost Software License 1.0.
 
#include <p/cppx/basics/io/stdstreams/external_stream_kind.hpp>
#include
<p/cppx/basics/io/stdstreams/iostreams_config/Console_narrow_encoding.hpp>
#include
<p/cppx/basics/io/stdstreams/iostreams_config/console_input_streambuffer_.hpp>
#include
<p/cppx/basics/io/stdstreams/iostreams_config/Console_output_streambuffer_.hpp>
#include <p/cppx/basics/io/stdstreams/streams_from_ids.hpp>
#include <p/cppx/core_language_support.hpp> //
cppx::Default_c_level_locale_setter
 
namespace progrock{ namespace cppx{
 
// This is probably idempotent, but there's no point calling it
more than once.
inline void configure_iostreams()
{
// We're dealing with changing apparently nonsense functionality.
// So it's difficult to say whether order is or can later become
// significant here, but the given order below feels safest. I.e.
// going inward from physical environs to software abstractions,
// so as to not change thing that X depends on after changing X.
 
// 1
// Set console active codepage to the one used for narrow literals.
// In Unixland the "codepage" will just be 0, with no effect.
int const codepage = atoi(
execution_character_set_encoding.c_str() );
static const Console_narrow_encoding using_encoding( codepage );
 
// 2
// Set the C level locale to the same codepage, if possible.
static const Default_c_level_locale_setter using_default_locale;
 
// 3
// Set the C++ global locale also to that codepage, if possible.
// With at least some g++ variants it's not possible, but happily
// with those compilers the wide streams apparently translate
// narrow strings according to the C level locale.
using std::locale;
try
{
// The default native locale with the C++ execution character
// set encoding, established by Default_c_level_locale_setter:
const auto specification = setlocale( LC_ALL, nullptr );
locale::global( locale( specification ) );
}
catch( ... )
{
// Could try just the default native locale, sans encoding,
// locale::global(locale("")); // but would reset C the level!
#ifndef __GNUC__ // g++'s can deal OK with things anyway.
throw;

No comments: