Discussion:
[PATCH] C++11 keyword fallback
Roger Leigh
2013-02-03 02:01:54 UTC
Permalink
The attached patch introduces three macros:
AC_CXX_CONSTEXPR
AC_CXX_FINAL
AC_CXX_NULLPTR
which behave like AC_C_CONST et al but are for the new
C++11 constextr, final and nullptr keywords. I can add
additional macros for other keywords, but not all of them
have the possibility of falling back e.g. decltype, so I
have excluded these for now since I don't see these as
being useful additions.

I would also like to add checks for a number of types which
have implementations in the std:: (C++11) and std::tr1 (C++98TR1)
and boost:: (Boost) namespaces. Examples: regex, tuple, memory.
In many projects, I have logic in compatibility headers such as
follows. In brief, these include the std:: header (if present)
or else include the std::tr1 header (if present) or else include
the boost:: header (if present) or else fail. This permits once
to use the C++11 types with fallback to C++98TR1 or Boost being
completely transparent.

Would including macros such as AC_CXX_MEMORY, AC_CXX_TUPLE,
AC_CXX_REGEX etc. be acceptable? If so, is it acceptable to
include logic similar to the following in config.h or an
alternate header? Does autoconf allow the user to specify
which header will be used to e.g. redirect C++-specific
stuff to a specific header?


Regards,
Roger


# ifdef HAVE_MEMORY_SHARED_PTR
# include <memory>
# elif HAVE_TR1_MEMORY
# include <tr1/memory>
namespace std {
using std::tr1::shared_ptr;
using std::tr1::weak_ptr;
using std::tr1::static_pointer_cast;
using std::tr1::const_pointer_cast;
using std::tr1::dynamic_pointer_cast;
}
# elif HAVE_BOOST_SHARED_PTR_HPP
# include <boost/shared_ptr.hpp>
namespace std {
using boost::shared_ptr;
using boost::weak_ptr;
using boost::static_pointer_cast;
using boost::const_pointer_cast;
using boost::dynamic_pointer_cast;
}
# else
# error A shared_ptr implementation is not available
# endif

# ifdef HAVE_TUPLE
# include <tuple>
# elif HAVE_TR1_TUPLE
# include <tr1/tuple>
namespace std {
using tr1::tuple;
using tr1::get;
}
# elif HAVE_BOOST_TUPLE_TUPLE_HPP
# include <boost/tuple/tuple.hpp>
namespace std {
using boost::tuple;
using boost::get;
}
# else
# error A tuple implementation is not available
# endif
--
.''`. Roger Leigh
: :' : Debian GNU/Linux http://people.debian.org/~rleigh/
`. `' schroot and sbuild http://alioth.debian.org/projects/buildd-tools
`- GPG Public Key F33D 281D 470A B443 6756 147C 07B3 C8BC 4083 E800
Miles Bader
2013-02-03 04:52:18 UTC
Permalink
Post by Roger Leigh
AC_CXX_CONSTEXPR
AC_CXX_FINAL
AC_CXX_NULLPTR
which behave like AC_C_CONST et al but are for the new
C++11 constextr, final and nullptr keywords.
All of these seem a bit questionable...

The problem with "final" is that it's not a normal keyword, and so
remains a valid identifier in C++11 programs and headers. Nulling it
out is probably a bad idea; even when a program decides to avoid it,
it cannot assume library headers won't use it.

When "constexpr" matters, it's often not really optional, and although
are cases where this isn't true, in general I'm not sure if an
implementation that just nulls-it-out is reasonable. [It seems to me
that the main case where constexpr can be safely nulled-out is library
header files etc, which may define something constexpr only as an aid
to external users. However such library headers, etc, should not
freely redefine keywords, and typically aren't autoconf'd at all.]

"nullptr" may be similarly problematic, as when used, it serves to
disambiguate overloads in cases where "0" won't...

I think the common thread here is that even when C++ programs are
written with certain constraints in mind (e.g. "don't use final") in
order to cooperate with their autoconf-iscation, they almost always
use external header files which they _don't_ control.

As such, maybe autoconf macros that explicitly took an identifier to
define would be safer.

E.g., "AC_CXX_FINAL([MY_PACKAGE_FINAL])" would define
"MY_PACKAGE_FINAL" to either be "final" or "". The package my-package
could then safely use MY_PACKAGE_FINAL with this autoconf-iscation in
mind, without worrying about conflicts with external headers.

-miles
--
The secret to creativity is knowing how to hide your sources.
--Albert Einstein
Roger Leigh
2013-02-03 19:27:00 UTC
Permalink
Post by Miles Bader
Post by Roger Leigh
AC_CXX_CONSTEXPR
AC_CXX_FINAL
AC_CXX_NULLPTR
which behave like AC_C_CONST et al but are for the new
C++11 constextr, final and nullptr keywords.
All of these seem a bit questionable...
I think the common thread here is that even when C++ programs are
written with certain constraints in mind (e.g. "don't use final") in
order to cooperate with their autoconf-iscation, they almost always
use external header files which they _don't_ control.
As such, maybe autoconf macros that explicitly took an identifier to
define would be safer.
E.g., "AC_CXX_FINAL([MY_PACKAGE_FINAL])" would define
"MY_PACKAGE_FINAL" to either be "final" or "". The package my-package
could then safely use MY_PACKAGE_FINAL with this autoconf-iscation in
mind, without worrying about conflicts with external headers.
If you feel that this would be generally useful, I'll be happy to
update the patch to do this. OTOH, if they all introduce extra
complications WRT replacement of non-keyword names as you mention
with "final", maybe this is best to leave until there's a demand
for such headers.


Regards,
Roger
--
.''`. Roger Leigh
: :' : Debian GNU/Linux http://people.debian.org/~rleigh/
`. `' schroot and sbuild http://alioth.debian.org/projects/buildd-tools
`- GPG Public Key F33D 281D 470A B443 6756 147C 07B3 C8BC 4083 E800
Paul Eggert
2013-02-03 21:02:04 UTC
Permalink
Post by Roger Leigh
AC_CXX_CONSTEXPR
AC_CXX_FINAL
AC_CXX_NULLPTR
which behave like AC_C_CONST et al but are for the new
C++11 constextr, final and nullptr keywords.
Sorry, I don't know C++, so I'm not really qualified to judge
the utility of these macros or of Miles's qualms about them,
but would his comments be addressed by Autoconf macros that
cause config.h to #define HAVE_CONSTEXPR rather than #defining
constexpr, etc.? Or would that just be too awkward? I guess
I don't know the usage scenario here.
Post by Roger Leigh
Would including macros such as AC_CXX_MEMORY, AC_CXX_TUPLE,
AC_CXX_REGEX etc. be acceptable?
Is the pattern the same for all these? If so, it sounds
like it'd be better to have one macro AC_CXX_STD and invoke
it via AC_CXX_STD([memory]), AC_CXX_STD([tuple]), etc.
Even if there are slight differences it still may be better
to have one "smart" macro rather than lots of macros with
repetitive innards.
Roger Leigh
2013-02-03 23:16:48 UTC
Permalink
Post by Paul Eggert
Post by Roger Leigh
AC_CXX_CONSTEXPR
AC_CXX_FINAL
AC_CXX_NULLPTR
which behave like AC_C_CONST et al but are for the new
C++11 constextr, final and nullptr keywords.
Sorry, I don't know C++, so I'm not really qualified to judge
the utility of these macros or of Miles's qualms about them,
but would his comments be addressed by Autoconf macros that
cause config.h to #define HAVE_CONSTEXPR rather than #defining
constexpr, etc.? Or would that just be too awkward? I guess
I don't know the usage scenario here.
My initial intention was that my substituting the keyword with
nothing, it would transparently allow code to build on non
C++11 compilers. HAVE_* would permit the user to do this
themselves if appropriate.

However, after looking into this a bit more, I'm becoming less
sure of the utility. In the case of nullptr, it's a type in
its own right (std::nullptr_t) which can be used to influence
template specialisation. So the substitution could easily
break code. Likewise for constexpr and final.
Post by Paul Eggert
Post by Roger Leigh
Would including macros such as AC_CXX_MEMORY, AC_CXX_TUPLE,
AC_CXX_REGEX etc. be acceptable?
Is the pattern the same for all these? If so, it sounds
like it'd be better to have one macro AC_CXX_STD and invoke
it via AC_CXX_STD([memory]), AC_CXX_STD([tuple]), etc.
Even if there are slight differences it still may be better
to have one "smart" macro rather than lots of macros with
repetitive innards.
The pattern is roughly the same. However... each needs a
bunch of different types importing into the std namespace, so
it's not /that/ slight. And for some (e.g. regex) the headers
are currently bust in GCC libstdc++ so need to be coupled with
a proper test instatiating and using the types to make sure they
work. We could certainly have a generic function like
AC_C_STD_TRY we pass all the details to.


Regards,
Roger
--
.''`. Roger Leigh
: :' : Debian GNU/Linux http://people.debian.org/~rleigh/
`. `' schroot and sbuild http://alioth.debian.org/projects/buildd-tools
`- GPG Public Key F33D 281D 470A B443 6756 147C 07B3 C8BC 4083 E800
Miles Bader
2013-02-04 08:51:01 UTC
Permalink
Post by Paul Eggert
but would his comments be addressed by Autoconf macros that
cause config.h to #define HAVE_CONSTEXPR rather than #defining
constexpr, etc.? Or would that just be too awkward? I guess
I don't know the usage scenario here.
Sure, that would work too.

configure.ac:
AC_CXX_FINAL()
my-common-header.h:
#if HAVE_FINAL
# define MY_PKG_FINAL final
#else
# define MY_PKG_FINAL
#endif

[My suggestions was just to have autoconf do that stuff too, and it
seems likely that in most cases people would want this. Even if
autoconf does, it's probably good to advertise the HAVE_... macro
anyway, in case some more complicated action is needed.]

The only crucial bit is that autoconf shouldn't be defining the
standard identifiers.

[The same is true of "const" in many cases as well (it can effect
overloading etc, in a way that means it can't simply be turned into a
nop), but I expect these days pretty much every significant compiler
supports const anyway, so the autoconfiscation never actually does
anything in practice...]

-miles
--
Somebody has to do something, and it's just incredibly pathetic that it
has to be us. -- Jerry Garcia
Paul Eggert
2013-02-04 16:23:18 UTC
Permalink
Post by Miles Bader
I expect these days pretty much every significant compiler
supports const anyway,
I think that was always true for C++, which is why the
issue never came up for 'const' and C++. There were
a few old C programs that used 'const' as identifiers,
but they had to get changed for C89 anyway. No old
.h files happened to use 'const' as an identifier, so
we lucked out.

In contrast, '#define final /**/' is likely to cause problems,
e.g., on Fedora 17, /usr/include/gcrypt-module.h does this:

extern "C" {

...

typedef struct gcry_md_spec
{
...
gcry_md_final_t final;
...
} gcry_md_spec_t;

...

}

Loading...