user1998012 user1998012 - 4 months ago 19
C++ Question

Is there a way to give dynamically values to to a templated function in C++?

The "hello, world" of template meta-programming can be considered the factorial code:

template <unsigned int n>
struct factorial {
enum { value = n * factorial<n - 1>::value };
};

template <>
struct factorial<0> {
enum { value = 1 };
};


So we can get the factorial by doing

cout << factorial<4>::value << endl; //It will print 24


But if I do:

int N = 4;
cout << factorial<N>::value << endl; //COMPILE ERROR


Is there a way to give dynamically values to to a templated function in C++?

Answer

This might work for you.

#include<iostream>
#include<array>
#include<utility>

//Only >=c++14 supports doubles in constexpr, so we're sticking to integers.
template<unsigned int I>
struct FAC {
    static constexpr uint64_t val = I * FAC<I-1>::val;
};

template<>
struct FAC<0> {
    static constexpr uint64_t val = 0;
};

template<>
struct FAC<1> {
    static constexpr uint64_t val = 1;
};

template<size_t ... I>
uint64_t factorial_impl(std::index_sequence<I...>, const unsigned int i) {
    constexpr std::array<uint64_t, sizeof...(I)> a = {FAC<I>::val...};

    return a[i];
}

uint64_t factorial(const unsigned int i) {
    return factorial_impl(std::make_index_sequence<22>(), i); //Can't store factorial values above index 22 without using floating-point values
}

int main() {
    std::cout << "Which factorial do you want? [1-22]: ";
    unsigned int index = 0;
    std::cin >> index;
    std::cout << "Value of " << index << " is " << factorial(index) << std::endl;
    return 0;
}

If you'd rather it work with doubles, you'll need a c++14-compliant compiler, but this slight modification should work:

#include <iostream>
#include<array>
#include<utility>

template<unsigned int I>
struct FAC {
    static constexpr double val = I * FAC<I-1>::val;
};

template<>
struct FAC<0> {
    static constexpr double val = 0;
};

template<>
struct FAC<1> {
    static constexpr double val = 1;
};

template<size_t ... I>
double factorial_impl(std::index_sequence<I...>, const unsigned int i) {
    constexpr std::array<double, sizeof...(I)> a = {FAC<I>::val...};

    return a[i];
}

double factorial(const unsigned int i) {
    return factorial_impl(std::make_index_sequence<170>(), i); //Values above 170 are infinite.
}

int main() {
    std::cout << "Which factorial do you want? [1-170]: ";
    unsigned int index = 0;
    std::cin >> index;
    std::cout << "Value of " << index << " is " << factorial(index) << std::endl;
    return 0;
}