how to calculate polynom coefficient at compile time? - c++

I need to calculate the initial guess for the newtons method at compile-time. I'd like to prevent this calculation from happening at runtime.
Usually, I'd solve this problem using the enum trick:
enum
{
a = make_coeff(...),
b = make_coeff(...),
c = make_coeff(...)
};
where a, b, c are coefficients and make_coeff() is a consteval/constexpr function. I can't use this approach this time, because the coefficients are of class type.
I have tried:
static constexpr coeff_type a[]{make_coeff(...), make_coeff(...), make_coeff(...)};
Would such an array of coefficients guarantee that make_coeff() will not be executed at runtime? Even though make_coeff() is marked consteval, gcc will happily generate code for it. But clang will not allow even a static constexpr array.
the errors clang gives are:
error: static variable not permitted in a constexpr function
error: cannot take address of consteval function 'make_coeff' outside of an immediate invocation
gcc is happy, but I am suspicious of what it is actually doing.
another thing I was thinking about is:
template <auto C>
constexpr auto coeff() noexcept
{
return C;
}
coeff<make_coeff(...)>();
since I can pass a coefficient as a non-type template parameter.
is a template array possible?
template <auto ...C>
decltype((C, ...)) const a[]{C...};
perhaps even something like:
template <std::size_t I, auto ...C>
auto get() noexcept
{
// ... easy to implement, but I'm not sure if it is worthwhile
}

Related

If I create a constexpr function to only generate a compile time constant, shouldn't there be a way to generate a constexpr value from the parameters?

I understand that constexpr function return values cannot be compile time constants until the function has returned. Thus this works:
template <typename...Ts>
constexpr auto f(Ts&&...args) {
auto value = std::tuple<Ts...>(args...);
return some_constexpr_transform_function(value);
}
constexpr auto vf = f(1, 2.3, 4);
However, for the case where the function's parameters are only compile time constants, and thus the function is capable of returning a compile time constant, one should be able to take those arguments and generate a compile time constant to do some compile time magic on it.
template <typename...Ts>
constexpr auto g(Ts&&...args) {
constexpr auto value = std::tuple<Ts...>(args...);
// do some compile time magic here on value, like:
static_assert(std::get<0>(value) == 1, "The first parameter must be 1.");
return some_constexpr_transform_function(value);
}
constexpr auto vg = g(1, 2.3, 4);
This is with the understanding that this function is no longer callable with runtime parameters. Alas this isn't the case. Instead I have to do some ugly indirection stuff, requiring things to look messy and putting initialization out of place:
namespace detail {
// Sorry future dev, I know that this init is better off below, but
// I have to make this look ugly to do compile time validation tests.
constexpr auto ugly_intermediate_constexpr_value = std::make_tuple(1, 2.3, 4);
static_assert(std::get<0>(ugly_intermediate_constexpr_value) == 1
, "The first parameter must be 1.");
}
template <typename...Ts>
constexpr auto h(std::tuple<Ts...>&& args) {
return some_constexpr_transform_function(args);
}
constexpr auto vh = h(detail::ugly_intermediate_constexpr_value);
Is there any talk about fixing this? This seems to be a pretty big deficiency.
NOTE: I'm currently using c++14, and I know that I didn't use the perfect forwarding idiom. It's irrelevant to the question.
The biggest problem with making parameters constexpr, one which even P1045 has trouble dealing with, has to do with things users want most to be able to do when doing constant expression coding. Consider the following code:
template<int v>
constexpr auto func()
{
if constexpr(v == 0)
return int{5};
else
return float{20.f};
}
So, what is decltype(func)? The answer is that there is no answer because the question is invalid. func is not a function; it is a template. Templates have no "type", so decltype makes no sense when applied to them.
Templates are constructs which generate new types/functions/variables, based on their template arguments. The above works in C++ because func<0> is a different function from func<1>. Therefore, decltype(func<0>) is a legitimate thing and can be a different type from decltype(func<1>).
Consider a hypothetical constexpr equivalent:
constexpr auto func2(constexpr int v)
{
if constexpr(v == 0)
return int{5};
else
return float{20.f};
}
OK: what is decltype(func2)? There can be no answer, because what func2 does depends on the arguments it is called with. In effect, func2 is not a function: it is really some kind of construct which generates a function based on arguments it is given. And C++ already has such a language construct.
It's called a "template".
This problem relates to more than just function return types (though that's a big one for metaprogramming and reflection). Consider something as simple as:
constexpr void func3(constexpr size_t sz)
{
std::array<int, sz> arr{};
//Other stuff.
}
The compiler needs to generate the code to value-initialize arr. But that will have to have a size that depends on sz. Indeed, the amount of stack space that is taken up depends on sz. So... how does that work?
Each function call with a different sz value effectively has to regenerate the internals of the function... in exactly the same way as a template would for a different template argument value.
Basically, any attempt to make constexpr parameters is going to confront the reality that these are just template parameters. It's going to have to build a mechanism that exactly parallels template instantiation.
And with C++20 already having class types as non-type template parameters, the only thing that's wanting is a bit of syntactic sugar, allowing you to invoke func(0) rather than func<0>().
So just use template parameters.

when to use template non-type classes or plain arguments in constexpr functions

I am very unclear when to use non-type template arguments (C++20) or normal arguments in constexpr functions. It's unclear to me, what the restrictions are and when to switch from pure parameters to non-type template parameters (see Live).
Here an example which illustrates the clunkiness with normal arguments:
template<typename Tuple, typename Pred>
constexpr auto getLambda(Tuple&& tuple, Pred&& pred)
{
return [=](auto I, auto J) {
return pred(std::get<I>(tuple), std::get<J>(tuple));
};
}
template<typename T>
struct A
{
constexpr A(T t) : val(t){};
T val;
};
int main()
{
static constexpr auto t = std::make_tuple(A{10.0}, A{1});
constexpr auto p = [](auto&& a, auto&& b) { return a.val < b.val; };
constexpr auto s = getLambda(t, p);
//constexpr auto b = s(1,0); // that does unfortunately not compile -> go back write differently... :-|||
}
Mostly I first try to use normal arguments like above, and after cumbersome fiddling with compile errors about non-constant expressions, try an approach with template<auto t> (non-type template paramters. Mostly having then two implementations one for each use-case (this seems stupid to me...)
Its sounds to me that modern generic programming with C++20 tends towards compile-time computations using constexpr together with some type-meta-programming.
Could anyone shed some light into this rather new "dark-corner" of C++. I probably misunderstand
when something is not a constant-expression and when it is...
The short version: Use non-type template parameter to set non-type template arguments (more general everywhere, where you need a constant expression) and normal arguments for everything else.
The thing about constexpr functions you always have to keep in mind is that they can also be called at runtime. So every normal argument is not necessarily a constant expression. Hence you cannot use it to provide a non-type template argument (as the I in std::get<I>).
Of course one could argue that when called to calculate a constexpr variable the passed arguments are always constant expressions and could be used as such also inside the function. But it would be unexpected if a constexpr function works at compile time but not anymore at runtime.
One could expect that with the new consteval keyword in C++20, one could use normal arguments to consteval functions in constant expressions, since we know that these arguments have to be constant expressions. But this does not seem to be the case: https://godbolt.org/z/guz7FQ Why this is the case I do not know. But in general I like the seperation between normal variables and non-type template arguments.

Using static constexpr member variables of a non-constexpr object as template arguments

I am writing a library where object parameters that are inherently static are built into the type using non-type template parameters. Doing this offers massive performance optimization over an implementation where these values are runtime values (small benchmarks measured at 10x, expected 5-7x). However, I find that C++ does not support this idiom very well. I am trying to refactor the library to make it easier to use by developers that aren't very familiar with templates or metaprogramming.
I would like to offer constexpr functions that simplify the extraction of static constexpr member variables (that are used to propogate the static values through the types), so that users do some basic metaprogramming without understanding the heavy machinery behind the scenes. For example,
#include <type_traits>
template <int A, int B>
class Example {
public:
static constexpr auto C = A + B;
private:
int b {0};
};
template <int A, int B>
constexpr auto getC(Example<A, B> e) { return decltype(e)::C; }
/**** USER CODE ****/
int main()
{
Example<1, 2> e;
Example<2, getC(e)> f;
}
This does not work, e being non-constexpr can be used in a constexpr context, even if you aren't using the value (strangely if Example had no runtime members, it would work). One could write decltype(e)::C instead, but if it's a reference they would have to std::remove_reference<decltype(C)>::type::C and of course they would have to know to do this, and know enough to get around common problems like the remove_reference call. And at that point we are off in the weeds for the typical programmer this library is meant for.
constexpr functions don't work, macros don't work with the type system so they are also insufficient, how else could I accomplish this?
You can use a macro to wrap
std::remove_reference<decltype(C)>::type::C
That would look like
#define getC(obj) std::remove_reference_t<decltype(obj)>::C
I chose a combination of Nathan's answer, and an answer that was deleted, for the implementation of getC.
template <typename T, typename = std::void_t<decltype(std::remove_reference_t<T>::C)>>
constexpr int getC_() { return std::remove_reference_t<T>::C; }
#define getC(e) (getC_<decltype(e)>())
The function does the heavy lifting and gives a good error message if you give it an invalid type thanks to the guard. And the macro does the messy (to a beginner) invocation in a way that can never fail on it's own.
getC(1); // error: 'C' is not a member of 'std::remove_reference<int>::type' {aka 'int'}

convert strongly typed enumerator to its underlying type in compilation time?

I understand that a strongly typed enumerator can be converted to its underlying type as:
template<typename E> constexpr
auto to_integral(E e) -> typename std::underlying_type<E>::type
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
However, this is working in run-time.
Since enumerators are there already in compilation time, is there a way to do such conversion during compilation time?
As herb sutter mentioned in the below link,
When does a constexpr function get evaluated at compile time?
constexpr functions will be evaluated at compile time when all its arguments are constant expressions and the result is used in a constant expression as well. A constant expression could be a literal (like 42), a non-type template argument (like N in template class array;), an enum element declaration (like Blue in enum Color { Red, Blue, Green };, another variable declared constexpr, and so on.
They might be evaluated when all its arguments are constant expressions and the result is not used in a constant expression, but that is up to the implementation.
The function you wrote is OK to be used at compile time.
template<typename E> constexpr
auto to_integral(E e) -> typename std::underlying_type<E>::type
{
return static_cast<typename> std::underlying_type<E>::type>(e);
}
enum class A : int { a };
static_assert(to_integral(A::a) == 0);
This should compile, indicating that the function can be ran at compile time.
However, constexpr functions only indicate that the function complies with all requirements to be executed at compile time. To enforce this being calculated (even at -O0), you need to make your variables also constexpr.
constexpr auto i = to_integral(A::a);
i = 42;
For a variable, the constexpr simply means: initialize at compile time. Afterwards, you can use it as if it was runtime.
In the example above, I'm convinced that most compilers will optimize the code regardless of the constexpr keyword. (Given -O2 or -O3) However if the code becomes more complex the constexpr is required to force them to optimize it, regardless of the cost.

Why isn't std::array::size static?

The size of std::array is known at compile time, but the size member function isn't static. Is there any reason for that? It's slightly inconvenient not to be able to calculate the size without instantiating an object. (Well, I know about std::tuple_size specialization, but it doesn't work for classes derived from std::array.)
There is no good reason for that. In fact, boost::array<T, N>, the precursor of std::array<T,N>, actually defines static size_t size(){return N;} (although a modern more useful version should use constexpr also).
I agree with the OP that this is an unfortunate omission and underexplotaition of the language features.
Problem
I faced this problem before and the logic leads to a couple of solutions. The OP situation is the following: you have a class that derives from std::array and you need to access to the size at compile time.
#include<array>
template<class T...>
struct myarray : std::array< something that depends on T... >{
... very cool functions...
};
and later you have
template<class Array, size_t N = ???>
functionOnArrayConcept(Array const& a){...}
Where you need to know N at compile time.
As it is now, there is no code ??? that you can write that works both for std::array and myarray, because std::tuple_size<myarray<...>> will not work.
Solution
(this was suggested by #T.C. here Access maximum template depth at compile? . I am just copying it here.)
template<class T, std::size_t N>
auto array_size_impl(const std::array<T, N>&)
-> std::integral_constant<std::size_t, N>;
template<class Array>
using array_size = decltype(array_size_impl(std::declval<const Array&>()));
template<class Array>
constexpr auto static_size() -> decltype(array_size<Array>::value){
return array_size<Array>::value;
}
template<class Array>
constexpr auto static_size(Array const&) -> decltype(static_size<Array>()){
return static_size<Array>();
}
Now you can use it as this:
template<class Array, size_t N = static_size<Array>()>
functionOnArrayConcept(Array const& a){...}
If you are using std::tuple_size already, unfortunately (I think) you need to specialize std::tuple_size for each of your derived classes:
namespace std{
template<class... T> // can be more complicated if myarray is not parametrized by classes only
struct tuple_size<myclass<T...>> : integral_constant<size_t, static_size<myclas<T...>>()>{};
}
(In my opinion this is caused by another mistake in the STL design that std::tuple_size<A> doesn't have the default template<class A> struct tuple_size : A::size(){}.)
The solutions beyond this point are near obsolete compared to #T.C.
solution described above. I'll keep them here for reference only.
Solution 1 (idiomatic)
If the function is decoupled from you class you have to use std::tuple_size because that is the only standard way of accessing the size of std::array at compile time. Therefore you have to do this, 1) provide a specialization of std::tuple_size and if you can control myclass, 2) std::array doesn't have static size() but your derived class could (that simplifies the solution).
So, this can be a pretty general solution within the framework of STD, that consists in the specialization of std::tuple_size.
(Unfortunately providing specialization in std:: sometimes is the only way to make real generic code. See http://en.cppreference.com/w/cpp/language/extending_std)
template<class... T>
struct myarray : std::array<...something that depends on T...>{
... very cool functions...
static constexpr size_t size(){return std::tuple_size<std::array<...something that depends on T...>>::value;}
};
namespace std{
// specialization of std::tuple_size for something else that `std::array<...>`.
template<class... T> // can be more complicated if myarray is not parametrized by classes only
struct tuple_size<myclass<T...>> : integral_constant<size_t, myclass<T...>::size()>{};
}
// now `functionOnArrayConcept` works also for `myarray`.
(static size_t size() can be called differently, and there may be other ways to deduce the size of the base of myarray without adding any static function to size.)
Note
In the compilers I tried the following trick doesn't work. If this worked, the whole discussion would be less important, because std::tuple_size wouldn't be so necessary.
template<class ArrayConcept, size_t N = ArrayConcept{}.size()> // error "illegal expression", `std::declval<ArrayConcept>()` doesn't work either.
functionOnArrayConcept(ArrayConcept const& a){...}
Conceptualization
Due to this shortcoming in the implementation (or specification?) of std::array by which the only way to extract the compile time size is through std::tuple_size. Then std::tuple_size is conceptually part of the necessary interface of std::array. Therefore when you inherit from std::array you have also "inherit" std::tuple_size in some sense. And unfortunately you need to do this for further derivations. This is the concept behind this answer.
Solution 2 (a GNU hack)
If you are using GNU's STD library (that includes gcc and clang), there is a hack that can be used without adding any code, and that is by using the _M_elems member which is of (member) type ::_AT_Type::_Type (a.k.a. type T[N]) of std::array<T, N>.
This function will effectively behave like a static function ::size() (except that it cannot be used for instances of an object) of std::array or any type derived from std::array.
std::extent<typename ArrayType::_AT_Type::_Type>::value
which can be wrapped into:
template<class ArrayType>
constexpr size_t array_size(){
return std::extent<typename ArrayType::_AT_Type::_Type>::value
}
This work because the member type _AT_Type::_Type is inherited. (I wonder why GNU left this implementation detail public. Another omission?)
Solution 3 (a portable hack)
Finally, a solution using template recursion one can figure out what is the dimension of the base std::array.
template<class Array, size_t N=0, bool B = std::is_base_of<std::array<typename Array::value_type, N>, Array>::value>
struct size_of : size_of<Array, N + 1, std::is_base_of<std::array<typename Array::value_type, N+1>, Array>::value>{};
template<class Array, size_t N>
struct size_of<Array, N, true> : std::integral_constant<size_t, N>{};
// this is a replacement for `static Array::size()`
template<class Array, size_t N = size_of<Array>::value>
constexpr size_t static_size(){return N;}
// this version can be called with an object like `static Array::size()` could
template<class Array, size_t N = size_of<Array>::value>
constexpr size_t static_size(Array const&){return N;}
This is how one will get:
struct derived : std::array<double, 3>{};
static_assert( static_size<std::array<double, 3>>() == 3 );
static_assert( static_size<derived>() == 3 );
constexpr derived d;
static_assert( static_size(d) == 3 );
If this function is called with some type unrelated to std::array, it will give a recursion error. If you want a "soft" error instead, you have to add the specialization.
template<class Array>
struct size_of<Array, 250, false> {};
where 250 stands for a large number but smaller than the recursion limit. (I don't know how to get this number automatically, I only know the the recursion limit in my compiler is 256.)
Since C++11 you can use std::tuple_size on std::array to obtain the size as a compile time constant. See
http://en.cppreference.com/w/cpp/container/array/tuple_size
It can indeed be static, however, this would break "container" interface which won't play well with other generic algorithms that do expect containers to have size() member function. There is nothing to worry about, though, as std::array::size() is a constexpr function, so there is absolutely no overhead associated with it.
UPDATE:
Mr. Jrok have pointed out that one can call static member functions with "normal" syntax. Below is an example when it won't:
#include <array>
struct array {
static unsigned int size()
{
return 0;
}
};
template <typename T>
static auto do_stuff(T& data) -> decltype(data.size())
{
typedef decltype(data.size()) size_type;
size_type (T::*size_calc)() const = &T::size;
size_type n = 0;
for (size_type i = 0, e = (data.*size_calc)(); i < e; ++i)
++n;
return n;
}
int main()
{
// Below is fine:
std::array<int, 5> data { 1, 2, 3, 4, 5 };
do_stuff(data);
// This, however, won't work as "size()" is not a member function.
#if 0
array fake;
do_stuff(fake);
#endif
}
array::size is constexpr, so unless the stored type has a constructor or destructor, the operation array_t().size() is very unlikely to have any runtime effect. You can embed it in a template argument to ensure it doesn't. It does otherwise look like runtime code, though.
I think that it's nonstatic simply for uniformity with other containers. For example, you can form a pointer-to-member-function to it. Discovering the true rationale of anything often takes tough research, though. It could be that the authors never thought of it.
The other thing that comes to mind is that some special functions such as operator () () cannot be static, so any opportunistic application of static can only be piecemeal. Generic problems are better solved in uniform fashion, even if it means changing the core language.
You can re-declare a same-typed empty std::array (which should get optimized out) and take the size of that. For example:
// Pretend this is an expensive initialization; e.g., a function return value.
std::array<char, 0x123> some_array{1,2,3};
using type_of_some_array = decltype(some_array);
// Find the size without accessing the array.
auto constexpr size_of_some_array = type_of_some_array().size();
std::cout << size_of_some_array << std::endl;
compiles to:
00000000004006f0 <main>:
4006f0: 48 83 ec 08 sub $0x8,%rsp
4006f4: be 23 01 00 00 mov $0x123,%esi
4006f9: bf 60 10 60 00 mov $0x601060,%edi
4006fe: e8 ad ff ff ff callq 4006b0 <_ZNSo9_M_insertImEERSoT_#plt>
...
[No issues found when using size_of_some_array as a template parameter: which was counter-alluded to in the comments on #Potatoswatter's answer.]
Note that the Microsoft Visual C++ doesn't currently support constexpr (http://msdn.microsoft.com/en-us/library/hh567368.aspx), so the following valid code won't work:
array<int,3> dog;
array<double, dog.size( )> cat;
The following class provides a compile time static variable:
/**
* hack around MSVC's 2012 lack of size for const expr
*/
template <typename T, int N>
struct vcarray : public std::array<T,N> {
static const size_t ArraySize= N;
};
which can be used as:
vcarray<double,3> cat;
vcarray<double,cat.ArraySize> dog;
In my opinion it does not make sense to make the size member function static insofar as it provides no added value. It is possible to make it static, but you gain nothing from it.
The way the array class is designed, you can query the size of a given array object without explicitly knowing/remembering its exact type (which includes its size) at that location where you need the size. This is a convenience, and it removes the opportunity to make copy/edit errors. You can write code like this:
std::array<int, 5> blah;
// 50 lines of code
do_something_with(blah.size()); // blah knows its size
As you can see, at the location where I'm consuming the array's size, I don't actually remember what it was, but my code will work anyway, regardless of what the value actually is, and regardless whether maybe one day I change the array's type to be a different size.
Since the size function merely returns a template parameter, the compiler can trivially prove that the return value is a compile-time constant and optimize accordingly too (the function is also constexpr, so you can also use the return value as template parameter or enumeration).
Now what will be different if we make the size member function static?
If size was a static function, you could still use the static member function in the exact same way (that is, on an object instance, in a "not static way"), but that would be "cheating". After all, this is something that already works anyway, whether the member is static or not.
Further, you now have the possibility of invoking the member function without an object instance. While this seems like a good thing at first glance it really is no advantage at all for the array class template (...where the returned size is a template parameter).
In order to call a member function without an object (that is, in a "static member function way"), you must properly qualify the function with the class name and its proper template parameters.
In other words, you must write something like:
std::array<int, 5> blah;
// 50 lines of code
do_something_with(std::array<int,5>::size()); // I must tell size what to return
Now what have we gained from calling the size function? Nothing at all. In order to call the function, we needed to provide the correct template parameters, which includes the size.
That means no more and no less than that we must supply the information that we wish to query. Calling the function doesn't tell us anything we didn't already know.