Recursive templates don't work as expected with static variables - c++

The code
#include <iostream>
using namespace std;
template<int n> struct Fibo { static int x; };
template<> int Fibo<0>::x = 1;
template<> int Fibo<1>::x = 1;
template<int n> int Fibo<n>::x = Fibo<n-1>::x + Fibo<n-2>::x; //marked line
int main() {
cout << Fibo<5>::x << endl;
cout << Fibo<4>::x << endl;
cout << Fibo<3>::x << endl;
cout << Fibo<2>::x << endl;
cout << Fibo<1>::x << endl;
cout << Fibo<0>::x << endl;
return 0;
}
outputs
0
0
1
2
1
1
in VC++. (According to user M M. it compiles as expected in gcc). When the compiler gets to the marked line with n=5 it doesn't compile that same line again for n=4, but just treats Fibo<4>::x as if it were declared with
template<> int Fibo<4>::x; // x defaults to 0
Why is that? Why does it work as expected when using
template<int n> struct Fibo { enum { x = Fibo<n-1>::x + Fibo<n-2>::x }; };
template<> struct Fibo<0> { enum { x = 1 }; };
template<> struct Fibo<1> { enum { x = 1 }; };
instead, but not with a static variable? And how do you fix the first code (without enum)?

The Standard is very clear on this:
14.7.1 Implicit instantiation [temp.inst]
9 The implicit instantiation of a class template does not cause any
static data members of that class to be implicitly instantiated.
All the calls in main() to your Fibo<n>::x for n > 1, are explicit instantiations, that through the Fibonnaci recursion will implicitly instantiate Fibo<n-1> and Fibo<n-2> but not their members x. This means that at those points, the static members x will be evaluated to their default initialization of 0. For n=1 and n=0, the compiler will see the explicit initialization values of 1. So effectively, you get the following computation
Fibo<5>::x --> Fibo<4>::x + Fibo<3>::x --> 0 + 0 = 0
Fibo<4>::x --> Fibo<3>::x + Fibo<2>::x --> 0 + 0 = 0
Fibo<3>::x --> Fibo<2>::x + Fibo<1>::x --> 0 + 1 = 1
Fibo<2>::x --> Fibo<1>::x + Fibo<0>::x --> 1 + 1 = 2
Fibo<1>::x --> 1
Fibo<0>::x --> 1
You need to instantiate the static member x before evaluating the Fibonacci recursion. You can do this through a static const int or enum member x, or through a function (possibly constexpr in C++11) as shown by #Jarod42.

I'm not sure if the initialization order of the static variables of template<int n> int Fibo<n>::x = Fibo<n-1>::x + Fibo<n-2>::x; is specified...
You may write this:
template <int N> struct Fibo { int operator()() const { static int x = Fibo<N - 1>()() + Fibo<N - 2>()(); return x; } };
template <> struct Fibo<1> { int operator()() const { static int x = 1; return x; } };
template <> struct Fibo<0> { int operator()() const { static int x = 1; return x; } };
The dependencies are respected.
[Edit]
In a case where the value may be modified (according to your comment), you may use similar technique but returning reference:
template <int N> struct Fibo {
private:
int& operator()() { static int x = Fibo<N - 1>()() + Fibo<N - 2>()(); return x; }
public:
int operator()() const { return const_cast<Fibo&>(*this)(); }
// This change Fibo<0> and Fibo<1> and then update value up to Fibo<N>.
int operator(int fibo0, int fibo1) {
int n_1 = Fibo<N - 1>()(fibo1, fibo2);
(*this)() = n_1 + Fibo<N - 2>()();
}
};
template <> struct Fibo<1> {
private:
int& operator()() { static int x = 1; return x; }
public:
int operator()() const { return const_cast<Fibo&>(*this)(); }
void operator(int fibo0, int fibo1) { Fibo<0>()(fibo0); (*this)() = fibo1; }
};
template <> struct Fibo<0> {
private:
int& operator()() { static int x = 1; return x; }
public:
int operator()() const { return const_cast<Fibo&>(*this)(); }
void operator(int fibo0) { (*this)() = fibo0; }
};

The solution presented by #Jarod42 appears overly complicated to me.
Consider instead the simpler code below.
template<int N>
struct fib {
static const int val = fib<N-1>::val + fib<N-2>::val;
};
template<>
struct fib<0> { static const int val = 0;};
template<>
struct fib<1> { static const int val = 1;};
int main() {
std::cout << fib<45>::val << "\n";
return 0;
}

Related

How implement a lookup utility class with an array member variable?

Live On Coliru
I need to implement a utility class for the purpose of lookup. The value of the internal array never changes after the initialization. My initial plan was to implement this class with the help of constexpr so that the expensive initialization can be done in compilation time. However, I am not able to come up with a good solution. So far, I can only figure out the following two methods. Both methods have drawbacks.
Method One:
The implementation looks complicate for such a simple task.
Method Two:
First, I assume the initialization is done in compilation time. Is this correct?
Second, the TwoClass::m_array really should be static instead of a member variable.
Is there a better way to implement this with c++20?
Thank you
#include <iostream>
#include <array>
using namespace std;
//== Method One
class OneClass
{
public:
uint32_t get(size_t index)
{
return m_array[index % 0xFF];
}
struct init_static_array
{
init_static_array()
{
// std::cout << "call init_static_array\n";
for (int i = 0; i < N; i++) {
m_array[i] = i * i + 10;
}
}
};
private:
static init_static_array m_init_static_array;
enum {N = 255};
static int m_array[N]; // this is a lookup table and NEVER will be changed!
};
int OneClass::m_array[] = {0};
OneClass::init_static_array OneClass::m_init_static_array{};
//== Method Two
class TwoClass
{
public:
constexpr TwoClass()
{
//std::cout << "call TwoClass::TwoClass()\n";
for (int i = 0; i < N; i++) {
m_array[i] = i * i + 10;
}
}
int get(size_t index) const
{
return m_array[index % 0xFF];
}
private:
enum {N = 255};
int m_array[N] {0}; // this is a lookup table and NEVER will be changed!
};
int main()
{
OneClass oneclass;
cout << "1 => " << oneclass.get(1) << std::endl;
cout << "256 => " << oneclass.get(256) << std::endl;
cout << "==================\n";
TwoClass twoclass;
cout << "1 => " << twoclass.get(1) << std::endl;
cout << "256 => " << twoclass.get(256) << std::endl;
return 0;
}
Output:
call init_static_array
1 => 11
256 => 11
==================
call TwoClass::TwoClass()
1 => 11
256 => 11
If it's C++20, don't you just want this:
namespace {
constexpr std::size_t N{255u};
consteval std::array<int, N> initArr()
{
std::array<int, N> arr{};
for (int i = 0; i < N; i++) {
arr[i] = i * i + 10;
}
return arr;
}
}
class C
{
private:
constexpr static std::array<int, N> arr{initArr()};
public:
constexpr C() = default;
int get(std::size_t n) const {return arr[n%255];}
};
Neither of your methods initialized the array at compile-time.
In the first method, the array is initialized in construction of static data member m_init_static_array, e.g. before main is called.
In the second method, constexpr in function declarations, including constructors, indicates that you want them being able to be called at compile-time, e.g. in evaluation of constant expressions. It doesn't mean all invocations are evaluated at compile-time. To call constexpr functions as compile-time, you have to call them in constant expression.
One solution is to initialize the static constexpr data member internal_array of type std::array by a lambda:
#include <array>
class Demo {
public:
int get(int index) const {
return internal_array[index % N];
}
private:
static inline constexpr int N = 255;
static inline constexpr std::array<int, N> internal_array = []() {
// Cannot call non-constexpr functions at compile-time
// std::cout << "std::cout << "call init_static_array\n";
std::array<int, N> arr;
for (int i = 0; i < N; ++i)
arr[i] = i * i + 10;
return arr;
}();
};
int main() {
Demo demo;
return demo.get(10);
}

How to fix class function behaviour based on initialization parameters

I am creating a C++ class which takes certain parameters during initialization and has some functions based on its private variables, something like the compute function here:
class A {
public:
A(int x){
a = x;
}
int compute(int y){
if (a == 0){
return y*y;
}
else if (a == 1){
return 2*y;
}
else{
return y;
}
}
private:
int a;
};
// usage
A myA(1); // private variables set only once
myA.compute(10); // this will check value of a
myA.compute(1); // this will check value of a
Given that the private variables are set during initialization and will not be changed again, is there any efficient way to avoid the condition check related to the private variables during runtime?
Any and all assistance is appreciated. Thank you
You can template the function compute() on an int and use the template value as parameter. You can see the result at https://godbolt.org/z/14Mh4E
class A {
public:
A(int x) {
a = x;
}
template <int y>
constexpr int compute() const {
if (a == 0) {
return y * y;
}
else if (a == 1) {
return 2 * y;
}
else {
return y;
}
}
private:
int a;
};
// usage
A myA(1); // private variables set only once
myA.compute<10>(); // this will check value of a
myA.compute<1>(); // this will check value of a
You could avoid the condition check if you would use e.g. a function object as a member, and set this conditioned on the value of variable a.
Anyway, I don't think that the condition check will be big performance issue. But this will depend on your application of course.
#include <functional>
#include <iostream>
class A {
public:
A(int x)
: a { x }
{
if (a == 0){
compute = [](int y){ return y*y; };
}
else if (a == 1){
compute = [](int y){ return 2*y; };
}
else{
compute = [](int y){ return y; };
}
}
std::function<int(int)> compute;
private:
int a;
};
// usage
int main()
{
A myA(1); // private variables set only once
std::cout << myA.compute(10) << std::endl;
std::cout << myA.compute(1) << std::endl;
return 0;
}
You can guarantee the conditions are evaluated at compile time by using constexpr. Note that in this case you must use C++14 for constexpr compute(...), as multiple return statements are only suppoerted in constexpr functions after C++14.
#include <iostream>
class A {
public:
constexpr A(const int x): a(x) { }
constexpr int compute(const int y) const {
// Multiple return statements inside a constexpr function
// requires C++14 or above.
if (a == 0) {
return y*y;
}
else if (a == 1) {
return 2*y;
}
else {
return y;
}
}
private:
int a;
};
int main() {
constexpr A myA(1);
constexpr int num = myA.compute(123);
std::cout << num << std::endl;
return EXIT_SUCCESS;
}
This page contains a good explanation of constexpr, as well as examples.
If parameters are runtime value, I don't see an optimal way to avoid condition or jump.
You can trade your condition by virtual call:
struct A
{
virtual ~A() = default;
virtual int compute(int) = 0;
};
struct A0 { int compute(int y) override { return y * y; } };
struct A1 { int compute(int y) override { return 2 * y; } };
struct AN { int compute(int y) override { return y; } };
std::unique_ptr<A> makeA(int a)
{
switch (a) {
case 0: return std::make_unique<A0>();
case 0: return std::make_unique<A1>();
default: return std::make_unique<AN>();
}
}
(compiler might devirtualize the call if type is known at compile time)
or "equivalent":
struct A
{
int (*f)(int); // or even std::function<int(int)> f; if you need capture.
A(int a) : f(a == 0 ? +[](int y) { return y * y; }
: a == 1 ? +[](int y) { return 2 * y; }
: +[](int y) { return y; })
{}
int compute(int y) { return f(y); }
};
(erased-type is harder for compiler to devirtualize)

Confused over template method specialization

I have been trying to understand this but can't get it to work. My impression is that this should work:-
template <int I> struct banana {
int getNumber() { return 5; }
int getNumber<0>() { return 6; }
};
So if I make a new banana with any template parameter other than 0, getNumber() should return 5 and if the parameter is 1, it should return 6. Why is it not working?
Because that's not the way to specialize. What you need is
#include <iostream>
template <int I> struct banana {
int getNumber() { return 5; }
//int getNumber<0>() { return 6; } // WRONG
};
template<> int banana<0>::getNumber(){ return 6;} // CORRECT WAY OF SPECIALIZING
int main()
{
banana<42> foo;
banana<0> bar;
std::cout << foo.getNumber() << std::endl; // outputs 5
std::cout << bar.getNumber() << std::endl; // outputs 6
}
Live on Coliru
There are 2 ways to get what you want... depending on what you want.
expanding on vsoftco's answer:
#include <iostream>
template <int I>
struct banana {
int getNumber() { return 5; }
};
template<>
struct banana<0>
{
int getNumber() { return 6; }
};
struct banana2
{
template<int I> int getNumber() { return 5; }
};
template<>
int banana2::getNumber<0>() { return 6; }
using namespace std;
auto main() -> int
{
banana<42> foo;
banana<0> bar;
std::cout << foo.getNumber() << std::endl;
std::cout << bar.getNumber() << std::endl;
banana2 b2;
std::cout << b2.getNumber<400>() << std::endl;
std::cout << b2.getNumber<0>() << std::endl;
return 0;
}
expected output:
5
6
5
6

What will the actual source code this template creates look like?

template <int N>
struct Factorial {
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0> {
enum { value = 1 };
};
const int x = Factorial<4>::value; // == 24
const int y = Factorial<0>::value; // == 1
After pre-compilation, if we could magically see what the compiler produced, would we actually see:
const int x = 24;
const int y = 1;
And would we see actual definitions for the struct Factorial, multiple of these? If so how would they look? I'm trying wrap my head around this part of the metaprogramming process.
Using g++ -fdump-tree-original on this code, I see the following result, which for this case seems to confirm your suspicion:
;; Function int main() (null)
;; enabled by -tree-original
{
const int x = 24;
const int y = 1;
<<cleanup_point const int x = 24;>>;
<<cleanup_point const int y = 1;>>;
}
return <retval> = 0;

Call map key to invoke function requiring a parameter - how to get working

Here is my code.
#include <map>
#include <string>
#include <algorithm>
class maptest {
public:
int doubler(int val) { return val * 2; }
int halver(int val) { return val / 2; }
int negativer(int val) { return val > 0 ? -val : val; }
};
int main() {
const char* const ID[] = {"doubler", "halver", "negativer" };
int ID_SIZE = sizeof(ID) / sizeof(*ID);
//signature of maths functions
typedef int (maptest::*mathfunc)(int);
mathfunc mfuncs[] = { &maptest::doubler, &maptest::halver, &maptest::negativer};
std::map<std::string, mathfunc> mathmap;
for(int i = 0; i < ID_SIZE; ++i) {
mathmap.insert(std::make_pair(ID[i], mfuncs[i]));
}
//C2064: term does not evaluate to a function taking 1 argument
int result = *mathmap["doubler"](3);
return 0;
}
I think this would work if there was no parameter to be passed to the functions. But how do I pass a parameter in this way?
Your mathfuncs are member functions, so you need an object on which to invoke them:
maptest mt;
int result = (mt.*(mathmap["doubler"]))(3);
Alternatively, you could make your member functions static:
class maptest {
public:
static int doubler(int val) { return val * 2; }
static int halver(int val) { return val / 2; }
static int negativer(int val) { return val > 0 ? -val : val; }
};
And then define mathfunc accordingly:
typedef int (*mathfunc)(int);
And this would allow you to invoke them the way you are invoking them in your original post:
typedef int (*mathfunc)(int);
Notice, that a way to make this design more flexible is to make use of std::function, which would allow you to pass any type of callable object. For instance:
typedef std::function<int(int)> mathfunc;
mathfunc mfuncs[] = {
&maptest::doubler,
&maptest::halver,
&maptest::negativer,
[] (int i) { return i * 2; } // <== A LAMBDA...
};
You are invoking non static member function.
do the following.
maptest t;
int (maptest::*tptr) (int) = mathmap["doubler"];
int result = (t.*tptr)(2);
Hope this helps.