This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: constexpr w/c++ stdlib features??
- From: Jonathan Wakely <jwakely at redhat dot com>
- To: "Linda A. Walsh" <gcc at tlinx dot org>
- Cc: libstdc++ at gcc dot gnu dot org
- Date: Thu, 22 May 2014 15:21:06 +0100
- Subject: Re: constexpr w/c++ stdlib features??
- Authentication-results: sourceware.org; auth=none
- References: <537D84FC dot 1040104 at tlinx dot org> <20140522121111 dot GI6953 at redhat dot com> <537DF7F1 dot 6020302 at tlinx dot org>
On 22/05/14 06:13 -0700, Linda A. Walsh wrote:
Jonathan Wakely wrote:
On 21/05/14 22:02 -0700, Linda A. Walsh wrote:
I'm trying to convert various 'C'-isms in my code.
I had something that "passed" the "constexpr-test",
namely, constexpr const char ** cpu_states_txt = {"USR", "Ni", "Sys"...};
This compiled and worked just fine. But I am trying to change it
to a vector or valarray:
constexpr const vector<const char *> const cpu_states_txt ={"Usr,
"...."};
Why do you need this to be constexpr?
If you really do nee it to be constexpr then you need to use a literal
type that can be initialized at compile-time.
---
I thought that since vector or valarray could have dimensions
specified at compile time,
This has dimensions specified at compile-time:
int* p = new int[5];
That doesn't make it a compile-time constant, it uses dynamic
allocation which is inherently a run-time behaviour.
then they might support compile time constants
as well. I didn't know the implementation couldn't use compile time
dimensions to allow it to be used as constexpr.
Is it a requirement that std::vector use runtime allocation if
the object it is representing is fixed at compile time or is that an
the result of implementation?
It's not possible for std::vector to tell the difference, so it's not
possible to implement it to choose to avoid run-time allocation.
As far as I'm aware the standard does not forbid the compiler from
optimising away dynamic allocation if it can statically prove there
will be no user-visible difference, but that would be a property of
the compiler not std::vector, and still wouldn't let you use
constexpr, because being able to declare the object as constexpr would
be a user-visible difference.
Optimisations are not supposed to change semantics, and declaring an
object constexpr has semantics that guarantee no non-trivial
initialization, it doesn't mean "please try to avoid non-trivial
initialization if the compiler happens to be smart enough and I enable
optimisations".
It *seemed*, that by tagging things as invariant (either at compile
or run time after some initialization), it could allow optimizations. in this
case, it would be the run-time code to initialize "resources" that are
statically fixed before the program starts execution.
A const vector is invariant at run-time after some initialization.
A constexpr object cannot have any run-time initialization. At all.
.... error: the type âconst std::vector<const
char*>â of constexpr variable âcpu_states_txtâ is not literal
Obviously since std::vector uses dynamic memory allocation it can't be
a compile-time constant.
Again, why do you need it to be constexpr?
What's wrong with just a const vector?
----
Nothing, but since it doesn't change and is present at compile
time, how would I let the invariant data be done at compile time
and not run time?
I don't know what "let the invariant data be done at compile time"
means, sorry.
What's wrong with simply:
const std::vector<const char*> cpu_states_txt{"USR", "Ni", "Sys"};
Why do you need that to be "done at compile-time"?
If you need other compile-time operations to use the array elements
either leave it as an array:
constexpr const char* cpu_states_txt[] = {"USR", "Ni", "Sys"};
Or use std::array
template<typename... T>
constexpr std::array<typename std::common_type<T...>::type,
sizeof...(T)>
make_array(T... t)
{
return { { t... } };
}
constexpr auto cpu_states_txt = make_array("USR", "Ni", "Sys");
You can even turn the former into the latter (using
make_index_sequence from C++14):
#include <array>
#include <iterator>
#include <utility>
template<typename T, std::size_t N, std::size_t... I>
constexpr std::array<T, N>
array2array_impl(const T (&a)[N], std::index_sequence<I...>)
{
return { { a[I]... } };
}
template<typename T, std::size_t N>
constexpr std::array<T, N>
array2array(const T (&a)[N])
{
return array2array_impl(a, std::make_index_sequence<N>{});
}
constexpr const char* cpu_states_txt[] = {"USR", "Ni", "Sys"};
constexpr auto states = array2array(cpu_states_txt);
There are loads of ways to skin this cat, but constexpr std::vector is
not one of them.
I'm trying to recode parts of this program in C++ specific
terms where it will decomplicate the code. Since it seems doable in 'C',
I wanted to figure out how to have C++ do it.
You can do what you did in C, that's valid C++ too.
(If it ain't broken don't fix it.)
Adding constexpr then changing to a non-trivial type is not the C++
way to do it, because it's not valid C++!
What you're trying to do with vector is not possible (and valarray is
almost certainly not what you want to use). You can either use a
constexpr std::array or use a const std::vector.