I am experimenting with basic template metaprogramming. I tried implementing structure templates which help us establish whether their template argument is prime or not. I.e.:
template<int N, int D>
struct IsPrime_Descend {
const static bool val = (N % D != 0) && IsPrime_Descend<N, D - 1>::val;
};
template<int N>
struct IsPrime_Descend<N, 1> {
const static bool val = true;
};
template <int N>
struct IsPrime {
const static bool val = IsPrime_Descend<N, N - 1>::val;
};
But the implementation above takes linear time. I wanted to boost it up to O(sqrt(n)). Of course, there is the long way of introducing a structure template for calculating the square root and descending from it:
template<int N, int D>
struct Sqrt_Descend {
const static int val = D * D > N ? Sqrt_Descend<N, D - 1>::val : D;
};
template<int N>
struct Sqrt_Descend<N, 1> {
const static int val = 1;
};
template<int N>
struct Sqrt {
const static int val = Sqrt_Descend<N, N>::val;
};
template<int N, int D>
struct IsPrime_Descend {
const static bool val = (N % D != 0) && IsPrime_Descend<N, D - 1>::val;
};
template<int N>
struct IsPrime_Descend<N, 1> {
const static bool val = true;
};
template <int N>
struct IsPrime {
const static bool val = IsPrime_Descend<N, Sqrt<N>::val>::val;
};
But there's something else I tried:
template <int N, int D>
struct IsPrime_Ascend {
const static bool val = (N % D != 0) && (D * D <= N) && IsPrime_Ascend<N, D + 1>::val;
};
template <int N>
struct IsPrime {
const static bool val = IsPrime_Ascend<N, 1>::val;
};
I reckoned this snippet to instantiate IsPrime_Ascend<N, D> as long as the two preceding conditions ((N % D != 0) && (D * D <= N)) are true due to the laziness of &&. But, apparently, it does not stop when one of them breaks and exceeds template instantiation maximum depth.
So, why is && strict (as in not lazy) in compile-time?
Short-circuit evaluation deals with evaluation of expressions. The expression is still there in the text of the C++ file, and it therefore must be compiled. If that expression contains a template instantiation, then that template must be instantiated. That's how compilation works (unless you use if constexpr, which you can't within that context).
If you want to prevent further instantiation, you have to do so via the rules of templates, not the rules of expression evaluation. So you need to use a partial specialization of the template, one which probably uses SFINAE techniques that is active when the condition is true. C++20 makes this easier with a requires clause.
Better still, turn IsPrime_Descend into a constexpr function.
Related
I want to sum the number from 1 to N-1 by TMP. so I wrote a source code as shown below, but an error template argument '(number - 1)' involves template parameter(s) occurred. Do you happen to know how to deal with this?
template <int number, int i = 1>
class Sum {
public:
static const int result = i + Sum<number, i + 1>::result;
};
template <int number>
class Sum<number, number - 1> {
public:
static const int result = number - 1;
};
int main () {
const int result = Sum<10>::result;
return 0;
}
GCC still follows the rule:
Non-type argument expression cannot use the name of the template parameter except when it is exactly the name of the template parameter.
To solve the problem using template specialization, you can wrap the second non-type template parameter into an std::integral_constant to make it a type template parameter:
template<int number, class i = std::integral_constant<int, 1>>
struct Sum {
static constexpr int value = i() + Sum<number,
std::integral_constant<int, i() + 1>>::value;
};
template<int number>
struct Sum<number, std::integral_constant<int, number - 1>> {
static constexpr int value = number - 1;
};
static_assert(Sum<10>::value == 45);
Alternatively, you can use if constexpr and no partial specialization:
template<int number, int i = 1>
struct Sum {
static constexpr int value = [] {
if constexpr (number == i + 1)
return i;
else
return i + Sum<number, i + 1>::value;
}();
};
static_assert(Sum<10>::value == 45);
Yet another way is given by fold expressions:
template<class> struct Sum_impl;
template<int... numbers>
struct Sum_impl<std::integer_sequence<int, numbers...>> {
static constexpr int value = (... + numbers);
};
template<int number>
struct Sum : Sum_impl<std::make_integer_sequence<int, number>> {};
Suppose I want to enable writing this:
template <int a,int b> struct add_base{ static const int value = a+b;};
template<int...a> using add = accumulate<add_base,0,a...>;
template <int a,int b> struct mult_base{ static const int value = a*b;};
template<int...a> using mult = accumulate<mult_base,1,a...>;
template <int a,int b> struct sqsum_base{ static const int value = a+b*b;};
template<int...a> using sqsum = accumulate<sqsum_base,0,a...>;
static_assert( add<1,2,3>::value == 6 );
static_assert( mult<2,2,2>::value == 8 );
static_assert( sqsum<1,2,3>::value == 14 );
My accumulate looks like this:
template <template <int,int> class G,
int first, int second,
int...more>
struct accumulate {
static const int value = accumulate<G,G<first,second>::value,more...>::value;
};
template <template <int,int> class G,
int first, int second>
struct accumulate<G,first,second> {
static const int value = G<first,second>::value;
};
Now I wonder if accumulate can be condensed by expanding the recusion inline, something like:
template <template <int,int> class G,
int first,int second,
int...more>
struct accumulate {
static const int value = G< G<first,second>::value , more...>::value;
};
This is wrong and will result in
error: Wrong number of template arguments (3 should be 2)
Is it possible to unpack the parameters to instantiate G recursively in one line? If not, how to write accumulate without having to write a specialization?
If your compiler has support for C++17 then you may want to utilize fold expression:
template<int ... x_item> struct
accumulate
{
static inline constexpr int const s_value{(0 + ... + x_item)};
};
static_assert(6 == accumulate<1, 2, 3>::s_value);
online compiler
Example of parametrized operation:
template<typename x_Op, int ... x_items> struct
accumulate
{
static inline constexpr int const s_value{(x_Op{0} + ... + x_Op{x_items}).value};
};
struct
sq_sum
{
int value;
};
inline constexpr sq_sum
operator +(sq_sum left, sq_sum right)
{
return sq_sum{left.value + right.value * right.value};
}
static_assert(14 == accumulate<sq_sum, 1, 2, 3>::s_value);
online compiler
I am trying to calculate GCD, at compile time using template partial specialization.
Following code works fine with clang3.8 but not with gcc7.1. With GCC, it's going into recursive template instantiation without realizing terminating case.
template <int N, int M>
struct GCD{
static const int value = (N>M)? GCD<N%M, M>::value : GCD<N, M%N>::value;
};
template <int M>
struct GCD<0, M>{
static const int value = M;
};
template <int M>
struct GCD<M, 0>{
static const int value = M;
};
int main()
{
static_assert(GCD<12,15>::value == 3, "Error");
}
Who is behaving sane here?
If you want to solve the problem, I propose the following improvement
template <int N, int M, bool = (M != 0) && (N != 0) && (N > M)>
struct GCD;
template <int N, int M>
struct GCD<N, M, true>
{ static constexpr int value { GCD<N%M, M>::value }; };
template <int N, int M>
struct GCD<N, M, false>
{ static constexpr int value { GCD<N, M%N>::value } ; };
template <int M>
struct GCD<0, M, false>
{ static constexpr int value { M }; };
template <int M>
struct GCD<M, 0, false>
{ static constexpr int value { M }; };
If you want to know if is right g++ or clang++, well... I don't know what, exactly, a compiler can or must do in this circumstances so... I don't know.
Precisely, I don't know, when N > M and a compiler encounter,
static const int value = (N>M)? GCD<N%M, M>::value : GCD<N, M%N>::value;
if the compiler must (or can) implement only GCD<N%M, M> or if must (or can) implement GCD<N, M%N> also.
Anyway, if I'm not wrong, clang++ implement only GCD<N%M, M> where g++ implement both.
My improvement is tailored to avoid this problem.
Consider this code:
template <int A, int B, typename T>
struct Object {
static constexpr bool check = A < B;
static constexpr int value = check ? A : A+1;
static constexpr char c = check ? 'a' : 'b';
static constexpr double d = check ? 1.5 : 3.14;
using type = typename std::conditional<check, T, int>::type;
// etc...
};
How to rewrite the above so that check needs only be checked once? After all, it is the same value throughout. Everything must be constexpr.
As commented by #Nawaz, the optimization is pointless. There will not be any runtime benefit and compiler is smart enough to optimize the conditions during compile time so there should not be much overhead during compile time.
In any case, what you are envisaging is possible, provided you agree to take the template specialization route. You can split the condition into two separate specialization and utilize them to determine the appropriate constexpr applicable for your problem.
template <int A, int B, typename T, bool check = A / B >
struct Object {
static constexpr int value = A;
static constexpr char c = 'a';
static constexpr double d = 1.5;
using type = T;
// etc...
};
template <int A, int B, typename T>
struct Object<A,B,T,false> {
static constexpr int value = A + 1;
static constexpr char c = 'b';
static constexpr double d = 3.14;
using type = int;
// etc...
};
You may pack all constant into tuple
template <int A, int B, typename T>
struct Object {
private:
static constexpr std::tuple<bool, int, char, double> t = (A < B) ?
{ true, A, 'a', 1.5 } :
{ false, B, 'b', 3.14};
public:
static constexpr bool check = std::get<0>(t);
static constexpr int value = std::get<1>(t);
static constexpr char c = std::get<2>(t);
static constexpr double d = std::get<3>(t);;
using type = typename std::conditional<check, T, int>::type;
// etc...
};
but not sure it was better.
I've a code smth like this:
template<int N, typename T>
class XYZ {
public:
enum { value = N };
//...
}
Is there a way to restrict N in some way? Specifically I want to allow compilation only if N is divided by some number, let's say 6.
So it turned out to be not just a type restriction.
Preferred way is to do this without Boost.
One C++03 approach:
template<int X, int Y>
struct is_evenly_divisible
{
static bool const value = !(X % Y);
};
template<int N, typename T, bool EnableB = is_evenly_divisible<N, 6>::value>
struct XYZ
{
enum { value = N };
};
template<int N, typename T>
struct XYZ<N, T, false>; // undefined, causes linker error
For C++11, you can avoid some boilerplate and give a nicer error message:
template<int N, typename T>
struct XYZ
{
static_assert(!(N % 6), "N must be evenly divisible by 6");
enum { value = N };
};
I leave this here for the future, since I couldn't find a good example online at the time of posting.
The C++20 way with concepts:
template<int X, int Y>
concept is_evenly_divisible = X % Y == 0;
template <int N, int M> requires is_evenly_divisible<N, M>
struct XYZ
{
enum class something { value = N };
};
XYZ<12, 6> thing; // OK
//XYZ<11, 6> thing; // Error
Or even shorter:
template <int N, int M> requires (N % M == 0)
struct XYZ
{
enum class something { value = N };
};