Usage of if constexpr in template - c++

I am trying to understand the utility of if constexpr and want to know if there is any utility in using it in this way.
template<bool B>
int fun()
{
if constexpr (B)
return 1;
return 0;
}
Is this function changed at all by using if constexpr instead of a regular if? I assume the performance would be the same. My understanding of templates is that the outcome of the if statement is already known at compile time so there is no difference.

Utility of constexpr?
A trivial example... if you write the following function
template <typename T>
auto foo (T const & val)
{
if ( true == std::is_same_v<T, std::string>> )
return val.size()
else
return val;
}
and call it with an integer
foo(42);
you get a compilation error, because the instruction
val.size();
has to be instantiated also when val is an int but, unfortunately, int isn't a class with a size() method
But if you add constexpr after the if
// VVVVVVVVV
if constexpr ( true == std::is_same_v<T, std::string>> )
return val.size()
now the return val.size(); instruction is instantiated only when T is std::string, so you can call foo() also with arguments without a size() method.
---- EDIT ----
As #prapin observed in a comment (thanks!), if constexpr can be necessary for an auto function.
I propose another trivial (and silly) example
Without if constexpr, the following bar() function
template <typename T>
auto bar (T const &)
{
if ( true == std::is_same_v<T, std::string>> )
return 42;
else
return 42L;
}
doesn't compile, because the first return return a int value, the second return a long; so, given that without if constexpr the compiler must instantiate both return's, so the compiler can't conciliate the returns types and can't determine the return type of the function.
With if constexpr,
if constexpr ( true == std::is_same_v<T, std::string>> )
return 42;
else
return 42L;
the compiler instantiate the first return or the second one; never both. So the compiler ever determine the type returned from the function (int when called with a std::string, long otherwise).

Related

How do I use concepts in if-constexpr?

How does one use concepts in if constexpr?
Given the example below, what would one give to if constexpr to return 1 in case T meets the requirements of integral and else 0?
template<typename T>
concept integral = std::is_integral_v<T>;
struct X{};
template<typename T>
constexpr auto a () {
if constexpr (/* T is integral */) {
return 1;
}
else {
return 0;
}
}
int main () {
return a<X>();
}
Concepts are named boolean predicates on template parameters, evaluated at compile time.
In a constexpr if statement, the value of the condition must be a contextually converted constant expression of type bool.
So in this case, usage is simple:
if constexpr ( integral<T> )
It is sufficient to do:
if constexpr ( integral<T> )
since integral<T> is already testable as bool

Why do I need to specify a return value for a function I'm passing to a Y combinator

I wrote a Y combinator like such:
template <class F>
struct Y{
F f;
Y(F _f) : f{_f} {}
template<class...arg_t>
auto operator()(arg_t&&...arg) {return f(*this,std::forward<arg_t>(arg)...);}
};
It works, but when I tried to define a factorial
auto fact = Y{[](auto&& self, int n) {
if (n<=1) return 1;
return n*self(n-1);}};
it would compile, but when I called it like f(3) clang got stuck on deducing the return type. With an explicit return type, it all worked fine. Is this a limitation of the template deduction? Is there a work-around?
I don't believe there is a way around it. You create a lambda with the following definition:
[](auto&& self, int n) {
if (n<=1) return 1;
return n*self(n-1);
}
This translates to:
struct lambda
{
template <typename T1>
constexpr auto operator()(T1&&self, int n) const
{
if (n<=1)
return 1;
return n*self(n-1);
}
};
Given that code, your compiler should deduce the return type as the common type of the 2 return statements.
With your template instation, it first needs to know the return type of your instantiation before it calculate the answer of that instantiation.
For this specific case, it might still be possible to deduce it correctly. What happens if you add extra indirections in between and recourse back to your type?
Type deduction is applied to the two return statements of the Y combinator, unconditionally, because the information held by the variable n is not a constant expression (an expression that is known by the compiler at compilation time). So the fixed point is not found by type deduction.
If n's value is known at compilation time, type deduction will succeed, example:
struct fact_overloads{
template<class Self,int n>
constexpr auto
operator()(Self&& self, std::integral_constant<n>){
if constexpr (n<=1) return 1;
else return n * self(std::integral_constant<n-1>{});
};
};
auto fact = Y{fact_overloads{}};
But such a function has a limited set of use cases because the value of n must be know at compil time.

Template parameters to constexpr

I am trying to pass a more "generic" const input parameter to a constexpr implementation for fibonacci. When I replace the template parameter with an int, things are hunky-dory again.
#include<iostream>
template <typename T>
constexpr auto fib_ce(T n) {
return (n>1) ? fib_ce(n-1)+fib_ce(n-2) : 1;
}
int main() {
std::cout<<fib_ce(4)<<"\n";
}
This is the error I get:
g++ -std=c++14 -o constexpr_fib constexpr_fib.cpp
constexpr_fib.cpp:4:19: fatal error: recursive template instantiation exceeded maximum depth of 256
return (n>1) ? fib_ce(n-1)+fib_ce(n-2) : 1;
^
How do I provide a template argument to a constexpr, that can take inputs like long, int, unsigned long, etc etc for this constexpr
The rule in [dcl.spec.auto] is:
If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression,
the program is ill-formed.
This is to just cut short the arbitrary complexity that could be infinite recursive deduction. Fear not though, there are ways around this problem:
Just use T instead of auto:
template <class T>
constexpr T fib_ce(T n) {
return (n>1) ? fib_ce(n-1)+fib_ce(n-2) : 1;
}
We also have the rule:
Once a non-discarded return statement has been seen in a function, however, the return type deduced from that statement can be used in the rest of the function, including in other return
statements.
So we can use an if statement instead of the conditional operator. We just have to invert the logic so that the return statement with known type goes first:
template <typename T>
constexpr auto fib_ce(T n) {
if (n <= 1) {
return static_cast<T>(1); // ok, deduced as T
}
else {
return fib_ce(n-1)+fib_ce(n-2); // we already deduced T, so sticking with it
}
}
Ok, I think I found the answer, need to refrain from auto and letting the compiler work the return type out here. The following works fine:
#include<iostream>
template <typename T>
constexpr T fib_ce(T n) {
return (n>1) ? fib_ce(n-1)+fib_ce(n-2) : 1;
}
int main() {
std::cout<<fib_ce(4)<<"\n";
}

Code executable in compile time and runtime [duplicate]

Lets say that you have a function which generates some security token for your application, such as some hash salt, or maybe a symetric or asymetric key.
Now lets say that you have this function in your C++ as a constexpr and that you generate keys for your build based on some information (like, the build number, a timestamp, something else).
You being a diligent programmer make sure and call this in the appropriate ways to ensure it's only called at compile time, and thus the dead stripper removes the code from the final executable.
However, you can't ever be sure that someone else isn't going to call it in an unsafe way, or that maybe the compiler won't strip the function out, and then your security token algorithm will become public knowledge, making it more easy for would be attackers to guess future tokens.
Or, security aside, let's say the function takes a long time to execute and you want to make sure it never happens during runtime and causes a bad user experience for your end users.
Are there any ways to ensure that a constexpr function can never be called at runtime? Or alternately, throwing an assert or similar at runtime would be ok, but not as ideal obviously as a compile error would be.
I've heard that there is some way involving throwing an exception type that doesn't exist, so that if the constexpr function is not deadstripped out, you'll get a linker error, but have heard that this only works on some compilers.
Distantly related question: Force constexpr to be evaluated at compile time
In C++20 you can just replace constexpr by consteval to enforce a function to be always evaluated at compile time.
Example:
int rt_function(int v){ return v; }
constexpr int rt_ct_function(int v){ return v; }
consteval int ct_function(int v){ return v; }
int main(){
constexpr int ct_value = 1; // compile value
int rt_value = 2; // runtime value
int a = rt_function(ct_value);
int b = rt_ct_function(ct_value);
int c = ct_function(ct_value);
int d = rt_function(rt_value);
int e = rt_ct_function(rt_value);
int f = ct_function(rt_value); // ERROR: runtime value
constexpr int g = rt_function(ct_value); // ERROR: runtime function
constexpr int h = rt_ct_function(ct_value);
constexpr int i = ct_function(ct_value);
}
Pre C++20 workaround
You can enforce the use of it in a constant expression:
#include<utility>
template<typename T, T V>
constexpr auto ct() { return V; }
template<typename T>
constexpr auto func() {
return ct<decltype(std::declval<T>().value()), T{}.value()>();
}
template<typename T>
struct S {
constexpr S() {}
constexpr T value() { return T{}; }
};
template<typename T>
struct U {
U() {}
T value() { return T{}; }
};
int main() {
func<S<int>>();
// won't work
//func<U<int>>();
}
By using the result of the function as a template argument, you got an error if it can't be solved at compile-time.
A theoretical solution (as templates should be Turing complete) - don't use constexpr functions and fall back onto the good-old std=c++0x style of computing using exclusively struct template with values. For example, don't do
constexpr uintmax_t fact(uint n) {
return n>1 ? n*fact(n-1) : (n==1 ? 1 : 0);
}
but
template <uint N> struct fact {
uintmax_t value=N*fact<N-1>::value;
}
template <> struct fact<1>
uintmax_t value=1;
}
template <> struct fact<0>
uintmax_t value=0;
}
The struct approach is guaranteed to be evaluated exclusively at compile time.
The fact the guys at boost managed to do a compile time parser is a strong signal that, albeit tedious, this approach should be feasible - it's a one-off cost, maybe one can consider it an investment.
For example:
to power struct:
// ***Warning: note the unusual order of (power, base) for the parameters
// *** due to the default val for the base
template <unsigned long exponent, std::uintmax_t base=10>
struct pow_struct
{
private:
static constexpr uintmax_t at_half_pow=pow_struct<exponent / 2, base>::value;
public:
static constexpr uintmax_t value=
at_half_pow*at_half_pow*(exponent % 2 ? base : 1)
;
};
// not necessary, but will cut the recursion one step
template <std::uintmax_t base>
struct pow_struct<1, base>
{
static constexpr uintmax_t value=base;
};
template <std::uintmax_t base>
struct pow_struct<0,base>
{
static constexpr uintmax_t value=1;
};
The build token
template <uint vmajor, uint vminor, uint build>
struct build_token {
constexpr uintmax_t value=
vmajor*pow_struct<9>::value
+ vminor*pow_struct<6>::value
+ build_number
;
}
In the upcoming C++20 there will be consteval specifier.
consteval - specifies that a function is an immediate function, that is, every call to the function must produce a compile-time constant
Since now we have C++17, there is an easier solution:
template <auto V>
struct constant {
constexpr static decltype(V) value = V;
};
The key is that non-type arguments can be declared as auto. If you are using standards before C++17 you may have to use std::integral_constant. There is also a proposal about the constant helper class.
An example:
template <auto V>
struct constant {
constexpr static decltype(V) value = V;
};
constexpr uint64_t factorial(int n) {
if (n <= 0) {
return 1;
}
return n * factorial(n - 1);
}
int main() {
std::cout << "20! = " << constant<factorial(20)>::value << std::endl;
return 0;
}
Have your function take template parameters instead of arguments and implement your logic in a lambda.
#include <iostream>
template< uint64_t N >
constexpr uint64_t factorial() {
// note that we need to pass the lambda to itself to make the recursive call
auto f = []( uint64_t n, auto& f ) -> uint64_t {
if ( n < 2 ) return 1;
return n * f( n - 1, f );
};
return f( N, f );
}
using namespace std;
int main() {
cout << factorial<5>() << std::endl;
}

How to ensure constexpr function never called at runtime?

Lets say that you have a function which generates some security token for your application, such as some hash salt, or maybe a symetric or asymetric key.
Now lets say that you have this function in your C++ as a constexpr and that you generate keys for your build based on some information (like, the build number, a timestamp, something else).
You being a diligent programmer make sure and call this in the appropriate ways to ensure it's only called at compile time, and thus the dead stripper removes the code from the final executable.
However, you can't ever be sure that someone else isn't going to call it in an unsafe way, or that maybe the compiler won't strip the function out, and then your security token algorithm will become public knowledge, making it more easy for would be attackers to guess future tokens.
Or, security aside, let's say the function takes a long time to execute and you want to make sure it never happens during runtime and causes a bad user experience for your end users.
Are there any ways to ensure that a constexpr function can never be called at runtime? Or alternately, throwing an assert or similar at runtime would be ok, but not as ideal obviously as a compile error would be.
I've heard that there is some way involving throwing an exception type that doesn't exist, so that if the constexpr function is not deadstripped out, you'll get a linker error, but have heard that this only works on some compilers.
Distantly related question: Force constexpr to be evaluated at compile time
In C++20 you can just replace constexpr by consteval to enforce a function to be always evaluated at compile time.
Example:
int rt_function(int v){ return v; }
constexpr int rt_ct_function(int v){ return v; }
consteval int ct_function(int v){ return v; }
int main(){
constexpr int ct_value = 1; // compile value
int rt_value = 2; // runtime value
int a = rt_function(ct_value);
int b = rt_ct_function(ct_value);
int c = ct_function(ct_value);
int d = rt_function(rt_value);
int e = rt_ct_function(rt_value);
int f = ct_function(rt_value); // ERROR: runtime value
constexpr int g = rt_function(ct_value); // ERROR: runtime function
constexpr int h = rt_ct_function(ct_value);
constexpr int i = ct_function(ct_value);
}
Pre C++20 workaround
You can enforce the use of it in a constant expression:
#include<utility>
template<typename T, T V>
constexpr auto ct() { return V; }
template<typename T>
constexpr auto func() {
return ct<decltype(std::declval<T>().value()), T{}.value()>();
}
template<typename T>
struct S {
constexpr S() {}
constexpr T value() { return T{}; }
};
template<typename T>
struct U {
U() {}
T value() { return T{}; }
};
int main() {
func<S<int>>();
// won't work
//func<U<int>>();
}
By using the result of the function as a template argument, you got an error if it can't be solved at compile-time.
A theoretical solution (as templates should be Turing complete) - don't use constexpr functions and fall back onto the good-old std=c++0x style of computing using exclusively struct template with values. For example, don't do
constexpr uintmax_t fact(uint n) {
return n>1 ? n*fact(n-1) : (n==1 ? 1 : 0);
}
but
template <uint N> struct fact {
uintmax_t value=N*fact<N-1>::value;
}
template <> struct fact<1>
uintmax_t value=1;
}
template <> struct fact<0>
uintmax_t value=0;
}
The struct approach is guaranteed to be evaluated exclusively at compile time.
The fact the guys at boost managed to do a compile time parser is a strong signal that, albeit tedious, this approach should be feasible - it's a one-off cost, maybe one can consider it an investment.
For example:
to power struct:
// ***Warning: note the unusual order of (power, base) for the parameters
// *** due to the default val for the base
template <unsigned long exponent, std::uintmax_t base=10>
struct pow_struct
{
private:
static constexpr uintmax_t at_half_pow=pow_struct<exponent / 2, base>::value;
public:
static constexpr uintmax_t value=
at_half_pow*at_half_pow*(exponent % 2 ? base : 1)
;
};
// not necessary, but will cut the recursion one step
template <std::uintmax_t base>
struct pow_struct<1, base>
{
static constexpr uintmax_t value=base;
};
template <std::uintmax_t base>
struct pow_struct<0,base>
{
static constexpr uintmax_t value=1;
};
The build token
template <uint vmajor, uint vminor, uint build>
struct build_token {
constexpr uintmax_t value=
vmajor*pow_struct<9>::value
+ vminor*pow_struct<6>::value
+ build_number
;
}
In the upcoming C++20 there will be consteval specifier.
consteval - specifies that a function is an immediate function, that is, every call to the function must produce a compile-time constant
Since now we have C++17, there is an easier solution:
template <auto V>
struct constant {
constexpr static decltype(V) value = V;
};
The key is that non-type arguments can be declared as auto. If you are using standards before C++17 you may have to use std::integral_constant. There is also a proposal about the constant helper class.
An example:
template <auto V>
struct constant {
constexpr static decltype(V) value = V;
};
constexpr uint64_t factorial(int n) {
if (n <= 0) {
return 1;
}
return n * factorial(n - 1);
}
int main() {
std::cout << "20! = " << constant<factorial(20)>::value << std::endl;
return 0;
}
Have your function take template parameters instead of arguments and implement your logic in a lambda.
#include <iostream>
template< uint64_t N >
constexpr uint64_t factorial() {
// note that we need to pass the lambda to itself to make the recursive call
auto f = []( uint64_t n, auto& f ) -> uint64_t {
if ( n < 2 ) return 1;
return n * f( n - 1, f );
};
return f( N, f );
}
using namespace std;
int main() {
cout << factorial<5>() << std::endl;
}