I had this question asked of me on Monday and for the life of me I don't know how to answer. Since I don't know, I now want to very much find out. Curiosity is killing this cat. Given two integers, return the lesser at compile time.
template<int M, int N>
struct SmallerOfMandN{
//and magic happenes here
};
Got pointers or how to do it? (Will start reading Boost MPL tonight.)
That is called the minimum of two numbers, and you don't need world heavy weight library like mpl to do such a thing:
template <int M, int N>
struct compile_time_min
{
static const int smaller = M < N ? M : N;
};
int main()
{
const int smaller = compile_time_min<10, 5>::smaller;
}
Of course if it was C++0x you could easily say:
constexpr int compile_time_min(int M, int N)
{
return M < N ? M : N;
}
int main()
{
constexpr int smaller = compile_time_min(10, 5);
}
Related
I'd like to create a type with a compile-time guarantee that instances are one of N possible values. The values are int types. No arithmetic needed.
One possible solution is to use an enum class, but this scales poorly with N.
I think the solution would look most like a fixed range int. I imagine the usage would look something like this, but i'm not too sure how to implement this.Is something like this possible or am I limited to enum classes?
constexpr auto N = 60;
MyType<N> foo(30); // okay
MyType<N> foo(0); // okay
MyType<N> foo(59); // okay
MyType<N> bar(60); // compile error
MyType<N> boo(-1); // compile error
I don't think it's possible to get compile error, however you can limit it using custom class something like this:
#include <stdexcept>
class MyIntger {
public:
MyIntger(int num){
if(num < Min || num > Max){
throw std::runtime_error("Number out of range");
}
value = num;
}
private:
int value;
const static int Min = 0;
const static int Max = 60;
};
int main(){
MyIntger a(5); // OK
MyIntger b(61); // Throws std::runtime_error
}
You can have compile-time ints in C++ (and thus compile-time limit checking), but syntax is not the same as for runtime ints:
#include <type_traits>
template<size_t N>
struct MyInteger
{
// you might have it as T or limit it to size_t
template<typename T, T I>
MyInteger(std::integral_constant<T, I>)
: value(I) { static_assert(I < N); }
size_t value;
};
int main()
{
MyInteger<60> a(std::integral_constant<size_t, 59>()); // ok
MyInteger<60> b(std::integral_constant<size_t, 60>()); // error
}
If you don't like the long name, you can always have a template type alias, e.g.:
template<size_t K>
std::integral_constant<size_t, K> I = {};
int main()
{
MyInteger<60> a(I<59>);
}
I'm not sure why the array creation in the function passes but not the one in the class even though array size is a compile time computable value.
template<int N>
int getPow()
{
int power = 1;
while(power < N)
power <<= 1;
return power;
}
template<int N>
class Test
{
private:
int data[getPow<N>()];
};
void testfun()
{
int test[getPow<2>()]; // passes
Test<10> t1; // Fails????
}
As getPow is not constexpr, it cannot be used in places which require constant expression (as C-array size).
int test[getPow<2>()]; // passes
. You unfortunately use VLA extension. It should not pass.
You might solve your issue with:
template <unsigned N>
constexpr unsigned getPow()
{
return 1 << N;
}
I have been reading this website for quite a while now but have just registered.
I have also used search which did not seem to be very helpful.
Here it is:
As I am having fun with C++ I come along "lazy evaluation" conception on the Internet. I am interested in creating something like a "lazy vector" which is defined with the function which takes N arguments and first N vector elements.
However, I have currently come across the issue with it. Let me point it out:
template<typename T, typename... A>
class llazy
{
public:
llazy(const std::function<T(A...)>& func, A... args) : func(func), vec({args...}), numArgs(sizeof...(args))
{}
const T& operator[](size_t index)
{
unsigned short tmp = 1;
//Here I want to stray from 2 elements to pass to function and make the number at least like 0-4
std::vector<size_t> v;
for (unsigned short i = 0; i < numArgs; i++)
v.emplace_back(vec.size() - tmp++);
//As you can see here, there are no issues(if the vector has enough elements ofc) with these two
unsigned long long i = vec.size() - 2, j = vec.size() - 1;
while (vec.size() < index + 1)
//So how do I pass all the vec[v[0]], vec[v[1]], etc... elements to the "func"?
//Maybe there is another way to achieve this, however, this is the Python which makes me think this is possible
vec.emplace_back(func(vec[i++], vec[j++]));
if (vec.size() >= index + 1)
return vec[index];
}
private:
const unsigned char numArgs;
const std::function<T(A...)> func;
std::vector<T> vec;
};
using ullong = unsigned long long;
int main()
{
llazy<ullong, ullong, ullong> l(std::function<ullong(ullong, ullong)>([](ullong i, ullong j) { return i + j; }), 1, 1);
l[20];
l[50];
l[1000];
return 0;
}
Thank you for your answers in advance.
UPD: Sure, the vector can be passed to the function, however, this makes the functions themselves a lot less readable(e.g. unsigned sum(unsigned, unsigned) is much more clear than unsigned sum(std::vector)).
How do I use the last N elements of a vector as a function parameters
You don't need to put those elements into a temporary vector.
Instead, the classical solution to that is to use a separate function (or a C++20 template lambda, if you feel fancy) with a std::index_sequence parameter (and a parameter pack of indices). With a pack expansion, you can easily extract last N elements from your vector, one way or another.
Something like this would work:
template <typename F, std::size_t ...I>
auto make_tuple_seq(std::index_sequence<I...>, F &&func)
{
return std::tuple{func(I)...};
}
int main()
{
std::vector v = {1,2,3,4,5,6};
const int n = 3;
auto t = make_tuple_seq(std::make_index_sequence<n>{},
[&](std::size_t i) {return v[v.size() - n + i];});
// Prints `456`.
std::cout << std::apply([](int x, int y, int z){return x*100 + y*10 + z;}, t) << '\n';
}
It shouldn't be hard to adapt this code for your needs.
I'm giving template metaprogramming a go. Here is a simple example I came up with:
template <int n>
struct N
{
static const int k = N<n-2>::k;
};
template<>
struct N<0>
{
static const int k = 0;
};
int main(int, char *[])
{
}
The above works. Note that k is defined as k = N<n-2>::k;
The following fails:
template <int n>
struct N
{
static const int k = N<n-3>::k;
};
template<>
struct N<0>
{
static const int k = 0;
};
int main(int, char *[])
{
cout << N<10>::k;
getchar();
}
Same code, except now k = N<n-3>:k; The compiler complains about the code being too complex. This limit seems fairly arbitrary, is there a way to modify it?
Your original recursion only terminates for even values of the template parameter n. You need two stop cases, for n == 0 and n == 1. In your revised example, you'd need 3 stop cases, or a stop case for n <= 0.
I want to calculate factorial at the compile-time. I found some way to solve the problem, but I want to know if there any another solution for this problem without using enum s. Here the solution using enum s.
#include <iostream>
template <int n>
struct fact
{
enum{value = n*fact<n-1>::value};
};
template<>
struct fact<1>
{
enum{value = 1};
};
int main()
{
std::cout << fact<10>::value;
}
If there is no another solution, please describe why the enum s are must.
While there are alternative notations, It's written that way because more compilers accept that enum-style notation. The language supports const integral-type class members with an inline initialization, but some compilers aren't compliant with the standard in that regard. On compilers that are compliant in this regard, the following works just fine:
#include <iostream>
template <unsigned int n>
struct fact
{
static const unsigned int value = n*fact<n-1>::value;
};
template<>
struct fact<0>
{
static const unsigned int value = 1;
};
int main()
{
std::cout << fact<10>::value << "\n";
}
Replace,
enum{value};
with,
static int const value; // or unsigned int
enums are must because they suppose to be resolved at compile time. Which assures that whatever result you calculated must have been done at compile time. Other such type is static int const (means any integral type).
To illustrate:
enum E {
X = strlen(s); // is an error, because X is a compile time constant
};
Alternatively, you can use static const members:
template <unsigned int n>
struct fact { static const unsigned int value = n * fact<n-1>::value; }