I have lots of strings each with size 8 or less.
I need to do lots of comparisons there using memcmp() / strcmp().
I wonder if comparisons will work faster if I convert all them to std::uint64_t. In this case, at least on theory comparison will be branch-less also will happen in single CPU operation.
Did anyone tried something similar?
Here is some test code that generate those numbers. I am assuming little endian machine.
I know code can be significantly simplified if I use htobe32() / htobe64().
#include <cstdint>
#include <algorithm> // std::reverse_copy
namespace rev_impl{
template<typename T>
T rev(const char *s){
T t;
char *pt = reinterpret_cast<char *>(&t);
std::reverse_copy(s, s + sizeof(T), pt);
return t;
}
}
inline uint32_t rev32(const char *s){
return rev_impl::rev<uint32_t>(s);
}
inline uint64_t rev64(const char *s){
return rev_impl::rev<uint64_t>(s);
}
#include <iostream>
#include <iomanip>
template<typename T>
void print_rev(const char *s){
constexpr auto w = sizeof(T) * 2;
std::cout << std::setw(w) << std::setfill('.') << std::hex << rev_impl::rev<T>(s) << '\n';
}
inline void print_rev32(const char *s){
return print_rev<uint32_t>(s);
}
inline void print_rev64(const char *s){
return print_rev<uint64_t>(s);
}
int main(){
print_rev64("\0\0\0\0\0\0\0a");
print_rev64("a\0\0\0\0\0\0\0");
print_rev32("Niki");
print_rev32("Nika");
print_rev32("Nikz");
}
here is test output:
..............61
6100000000000000
4e696b69
4e696b61
4e696b7a
If you have to convert only string literals, you can write rev to accept array of chars as follows
template <typename T, std::size_t N,
typename = typename std::enable_if<(N<=sizeof(T)+1U)>::type>
constexpr T rev (char const (&arr)[N])
{
T ret = 0;
std::size_t ui = -1;
while ( ++ui < N-1U )
ret <<= CHAR_BIT, ret |= arr[ui];
while ( ++ui < sizeof(T) )
ret <<= CHAR_BIT;
return ret;
}
Observe that, starting from C++14, this function can be defined constexpr, so you can write something as
constexpr auto fb = rev<std::uint64_t>("foobar");
The following is you code rewritten to use string literals
#include <cstdint>
#include <climits>
#include <iostream>
#include <iomanip>
#include <type_traits>
namespace rev_impl
{
template <typename T, std::size_t N,
typename = typename std::enable_if<(N<=sizeof(T)+1U)>::type>
T rev (char const (&arr)[N])
{
T ret = 0;
std::size_t ui = -1;
while ( ++ui < N-1U )
ret <<= CHAR_BIT, ret |= arr[ui];
while ( ++ui < sizeof(T) )
ret <<= CHAR_BIT;
return ret;
}
}
template <typename T, std::size_t N>
inline uint32_t rev32 (char const (&s)[N])
{ return rev_impl::rev<uint32_t>(s); }
template <typename T, std::size_t N>
inline uint64_t rev64 (char const (&s)[N])
{ return rev_impl::rev<uint64_t>(s); }
template<typename T, std::size_t N>
void print_rev (char const (&s)[N])
{
constexpr auto w = sizeof(T) * 2;
std::cout << std::setw(w) << std::setfill('.') << std::hex
<< rev_impl::rev<T>(s) << '\n';
}
template <std::size_t N>
inline void print_rev32 (char const (&s)[N])
{ return print_rev<uint32_t>(s); }
template <std::size_t N>
inline void print_rev64 (char const (&s)[N])
{ return print_rev<uint64_t>(s); }
int main ()
{
print_rev64("\0\0\0\0\0\0\0a");
print_rev64("a\0\0\0\0\0\0\0");
print_rev32("Niki");
print_rev32("Nika");
print_rev32("Nikz");
}
Related
The following code attempts to create a typesafe way to generate byte-backed binary data while automatically generating metadata describing the bytes.
Is there any way to generate the metadata at compile time? For example:
const Type meta[] = {Type::U32, Type::U64};
I'm not even sure that's possible, but if it is please tell me how!
#include <iostream>
using namespace std;
enum class Type { U8, U16, U32, U64, I8, I16, I32, I64, F32, F64, STRUCT };
void write(char*& buf, uint32_t val) {
*(uint32_t*)buf = val;
buf += sizeof(uint32_t);
}
void write(char*& buf, uint64_t val) {
*(uint64_t*)buf = val;
buf += sizeof(uint64_t);
}
void writeMeta(char*& buf, uint32_t val) {
*(uint8_t*)buf = uint32_t(Type::U32);
buf += sizeof(uint8_t);
}
void writeMeta(char*& buf, uint64_t val) {
*(uint8_t*)buf = uint32_t(Type::U64);
buf += sizeof(uint8_t);
}
void writeBuf(char* buf, char*meta) {
}
template<typename T, typename ...Args>
void writeBuf(char* buf, char*meta, T first, Args... args) {
write(buf, first);
writeMeta(meta, first);
writeBuf(buf, meta, args...);
}
int main() {
char buffer[1024];
char metadata[1024];
writeBuf(buffer, metadata, uint32_t(2), uint64_t(3));
for (int i = 0; i < 12; i++)
cout << uint32_t(uint8_t(buffer[i])) << ' ';
cout << '\n';
}
As I understand, you want something like (C++17):
template <typename T>
constexpr Type toType()
{
if constexpr (std::is_same_v<uint8_t, T>) { return Type::U8; }
else if constexpr (std::is_same_v<uint16_t, T>) { return Type::U16; }
else if constexpr (std::is_same_v<uint32_t, T>) { return Type::U32; }
// ...
else { return Type::STRUCT; }
}
template <typename ...Ts>
constexpr std::array<Type, sizeof...(Ts)> getMeta()
{
return {{toType<Ts>()...}};
}
static_assert(getMeta<std::uint32_t, std::uint64_t>() == {Type::U32, Type::U64});
I have a class with an int template parameter. Under some circumstances I want it to output an error message. This message should be a concatenated string from some fixed text and the template parameters. For performance reasons I'd like to avoid building up this string at runtime each time the error occurs and theoretically both, the string literal and the template parameter are known at compiletime. So I'm looking for a possibility to declare it as a constexpr.
Code example:
template<int size>
class MyClass
{
void onError()
{
// obviously won't work but expressing the concatenation like
// it would be done with a std::string for clarification
constexpr char errMsg[] = "Error in MyClass of size " + std::to_string (size) + ": Detailed error description\n";
outputErrorMessage (errMsg);
}
}
Using static const would allow to compute it only once (but at runtime):
template<int size>
class MyClass
{
void onError()
{
static const std::string = "Error in MyClass of size "
+ std::to_string(size)
+ ": Detailed error description\n";
outputErrorMessage(errMsg);
}
};
If you really want to have that string at compile time, you might use std::array, something like:
template <std::size_t N>
constexpr std::size_t count_digit() {
if (N == 0) {
return 1;
}
std::size_t res = 0;
for (int i = N; i; i /= 10) {
++res;
}
return res;
}
template <std::size_t N>
constexpr auto to_char_array()
{
constexpr auto digit_count = count_digit<N>();
std::array<char, digit_count> res{};
auto n = N;
for (std::size_t i = 0; i != digit_count; ++i) {
res[digit_count - 1 - i] = static_cast<char>('0' + n % 10);
n /= 10;
}
return res;
}
template <std::size_t N>
constexpr std::array<char, N - 1> to_array(const char (&a)[N])
{
std::array<char, N - 1> res{};
for (std::size_t i = 0; i != N - 1; ++i) {
res[i] = a[i];
}
return res;
}
template <std::size_t ...Ns>
constexpr std::array<char, (Ns + ...)> concat(const std::array<char, Ns>&... as)
{
std::array<char, (Ns + ...)> res{};
std::size_t i = 0;
auto l = [&](const auto& a) { for (auto c : a) {res[i++] = c;} };
(l(as), ...);
return res;
}
And finally:
template<int size>
class MyClass
{
public:
void onError()
{
constexpr auto errMsg = concat(to_array("Error in MyClass of size "),
to_char_array<size>(),
to_array(": Detailed error description\n"),
std::array<char, 1>{{0}});
std::cout << errMsg.data();
}
};
Demo
Here's my solution. Tested on godbolt:
#include <string_view>
#include <array>
#include <algorithm>
void outputErrorMessage(std::string_view s);
template<int N> struct cint
{
constexpr int value() const { return N; }
};
struct concat_op {};
template<std::size_t N>
struct fixed_string
{
constexpr static std::size_t length() { return N; }
constexpr static std::size_t capacity() { return N + 1; }
template<std::size_t L, std::size_t R>
constexpr fixed_string(concat_op, fixed_string<L> l, fixed_string<R> r)
: fixed_string()
{
static_assert(L + R == N);
overwrite(0, l.data(), L);
overwrite(L, r.data(), R);
}
constexpr fixed_string()
: buffer_ { 0 }
{
}
constexpr fixed_string(const char (&source)[N + 1])
: fixed_string()
{
do_copy(source, buffer_.data());
}
static constexpr void do_copy(const char (&source)[N + 1], char* dest)
{
for(std::size_t i = 0 ; i < capacity() ; ++i)
dest[i] = source[i];
}
constexpr const char* data() const
{
return buffer_.data();
}
constexpr const char* data()
{
return buffer_.data();
}
constexpr void overwrite(std::size_t where, const char* source, std::size_t len)
{
auto dest = buffer_.data() + where;
while(len--)
*dest++ = *source++;
}
operator std::string_view() const
{
return { buffer_.data(), N };
}
std::array<char, capacity()> buffer_;
};
template<std::size_t N> fixed_string(const char (&)[N]) -> fixed_string<N - 1>;
template<std::size_t L, std::size_t R>
constexpr auto operator+(fixed_string<L> l, fixed_string<R> r) -> fixed_string<L + R>
{
auto result = fixed_string<L + R>(concat_op(), l , r);
return result;
};
template<int N>
constexpr auto to_string()
{
auto log10 = []
{
if constexpr (N < 10)
return 1;
else if constexpr(N < 100)
return 2;
else if constexpr(N < 1000)
return 3;
else
return 4;
// etc
};
constexpr auto len = log10();
auto result = fixed_string<len>();
auto pow10 = [](int n, int x)
{
if (x == 0)
return 1;
else while(x--)
n *= 10;
return n;
};
auto to_char = [](int n)
{
return '0' + char(n);
};
int n = N;
for (int i = 0 ; i < len ; ++i)
{
auto pow = pow10(10, i);
auto digit = to_char(n % 10);
if (n == 0 && i != 0) digit = ' ';
result.buffer_[len - i - 1] = digit;
n /= 10;
}
return result;
}
template<int size>
struct MyClass
{
void onError()
{
// obviously won't work but expressing the concatenation like
// it would be done with a std::string for clarification
static const auto errMsg = fixed_string("Error in MyClass of size ") + to_string<size>() + fixed_string(": Detailed error description\n");
outputErrorMessage (errMsg);
}
};
int main()
{
auto x = MyClass<10>();
x.onError();
}
Results in the following code:
main:
sub rsp, 8
mov edi, 56
mov esi, OFFSET FLAT:MyClass<10>::onError()::errMsg
call outputErrorMessage(std::basic_string_view<char, std::char_traits<char> >)
xor eax, eax
add rsp, 8
ret
https://godbolt.org/z/LTgn4F
Update:
The call to pow10 is not necessary. It's dead code which can be removed.
Unfortunately your options are limited. C++ doesn't permit string literals to be used for template arguments and, even if it did, literal concatenation happens in the preprocessor, before templates come into it. You would need some ghastly character-by-character array definition and some manual int-to-char conversion. Horrible enough that I can't bring myself to make an attempt, and horrible enough that to be honest I'd recommend not bothering. I'd generate it at runtime, albeit only once (you can make errMsg a function-static std::string at least).
I'm looking for a small function that is able to transform a std::array by adding increasing values. The function must be a compile time function.
I was able to write a small constexpr function which does so for an array of length 3, but I was unable to generalize it to std::arrays of arbitrary lengths. I also failed to generalize it to contain something different than chars.
Does anyone knows how to do it?
#include <array>
#include <iostream>
#include <valarray>
constexpr std::array<char,3> obfuscate(const std::array<char,3>& x) {
return std::array<char, 3>{x.at(0)+1, x.at(1) + 2, x.at(2) + 3 };
}
/* Won't compile
template<typename T,typename S, template<typename, typename> L=std::array<T, U>>
constexpr L<T,U> obfuscate(const L<T, U>& x) {
return {x.at(0) + 1, x.at(0) + 2, x.at(0) + 3 };
}
*/
std::ostream& operator<<(std::ostream& str, const std::array<char, 3>& x) {
for (auto i = 0; i < 3; i++) {
str << x.at(i);
}
return str;
}
int main(int argc, char** args) {
std::array<char, 3> x{ 'a','b','c' };
std::cout << x << std::endl;
std::cout << obfuscate(x) << std::endl;
// std::cout << obfuscate<3>(x) << std::endl;
}
You can use std::index_sequence:
template<class T, std::size_t N, std::size_t... Is>
constexpr std::array<T, N> helper (const std::array<T, N> &x, std::index_sequence<Is...>) {
return std::array<T, N>{static_cast<T>(x.at(Is)+Is+1)...};
}
template<class T, std::size_t N>
constexpr std::array<T, N> obfuscate(const std::array<T, N> &x) {
return helper(x, std::make_index_sequence<N>{});
}
There are a few methods that use tuple packs, these are great except that MSVC has a performance problem compiling large strings.
I've found this compromise works well in MSVC.
template<typename I>
struct encrypted_string;
template<size_t... I>
struct encrypted_string<std::index_sequence<I...>>
{
std::array<char, sizeof...(I)+1> buf;
constexpr static char encrypt(char c) { return c ^ 0x41; }
constexpr static char decrypt(char c) { return encrypt(c); }
constexpr explicit __forceinline encrypted_string(const char* str)
: buf{ encrypt(str[I])... } { }
inline const char* decrypt()
{
for (size_t i = 0; i < sizeof...(I); ++i)
{
buf[i] = decrypt(buf[i]);
}
buf[sizeof...(I)] = 0;
return buf.data();
}
};
#define enc(str) encrypted_string<std::make_index_sequence<sizeof(str)>>(str)
And somewhere later
auto stringo = enc(R"(
kernel void prg_PassThru_src(const global unsigned short * restrict A, int srcstepA, int srcoffsetA,
global float * restrict Beta, int srcstepBeta, int srcoffsetBeta,
int rows, int cols) {
int x = get_global_id(0);
int y0 = get_global_id(1);
if (x < cols) {
int srcA_index = mad24(y0, srcstepA / 2, x + srcoffsetA / 2);
int srcBeta_index = mad24(y0, srcstepBeta / 4, x + srcoffsetBeta / 4);
Beta[srcBeta_index] = A[srcA_index];
}
}
//somewhere later
cv::ocl::ProgramSource programSource(stringo.decrypt());
You can see this guy's talk for more sophisticated methods:
https://www.blackhat.com/docs/eu-14/materials/eu-14-Andrivet-C-plus-plus11-Metaprogramming-Applied-To-software-Obfuscation.pdf
I need to store the array of first N Fibonacci numbers.
const int N = 100;
long long int fib[N] = {0};
fib[0] = 1;
fib[1] = 1;
for(int i = 2; i < N; ++i)
fib[i] = fib[i-2] + fib[i-1];
return 0;
Is it possible to make fib[] constexpr, and evaluate it at compilation time somehow ?
First of all you have to write Fibonacci algorithm in compile time version, so consider following:
template <size_t N>
struct Fibo {
static constexpr const size_t value {Fibo<N-2>::value + Fibo<N-1>::value};
};
template <>
struct Fibo<0> {
static constexpr const size_t value {1};
};
template <>
struct Fibo<1> {
static constexpr const size_t value {1};
};
and you can use this as simply as that:
std::cout << Fibo<0>::value << std::endl;
std::cout << Fibo<1>::value << std::endl;
std::cout << Fibo<2>::value << std::endl;
std::cout << Fibo<3>::value << std::endl;
std::cout << Fibo<10>::value << std::endl;
std::cout << Fibo<50>::value << std::endl;
and output values are:
1
1
2
3
89
20365011074
But this is still not you are looking for.
I do not know if you can make constexpr array (but probably there is a possibility), but you can do it slightly different. Consider:
template <size_t N>
struct Storage {
static size_t data[N+1];
};
template <size_t N> size_t Storage<N>::data[N+1] {};
template <size_t N, size_t F>
struct Filler {
static constexpr void fill () {
Storage<N>::data[F] = Fibo<F>::value;
Filler<N, F-1>::fill ();
}
};
template <size_t N>
struct Filler<N, 0> {
static constexpr void fill () {
Storage<N>::data[0] = Fibo<0>::value;
}
};
template <size_t N>
struct Calc {
static constexpr void calc () {
Filler<N, N>::fill ();
}
};
and the usage would be like this:
constexpr const size_t N = 12;
Calc<N>::calc ();
size_t* ptr = Storage<N>::data;
for (int i = 0; i <= N; ++i) {
std::cout << ptr[i] << std::endl;
}
and output:
1
1
2
3
5
8
13
21
34
55
89
144
233
What is important here is the Storage class which stores our array with appropriate number of elements.
General Filler class (with two template parameters) is used for any F value that can be passed, except value of 0. Because if we reach the 0 index, we don't want to call once again fill() member function, because we are done. So that's the reason why partial specialization of Filler class exists.
Hope I can help with this.
There is a way (ugly one), but I can't think of anything else.
#include <iostream>
#include <cmath>
constexpr unsigned long long f(int x)
{
return 1/sqrt(5)*pow(((1+sqrt(5))/2),x) - 1/sqrt(5)*pow(((1-sqrt(5))/2),x);
}
#define FIBB1(x) 1
#define FIBB2(x) FIBB1(x-1),1
#define FIBB3(x) FIBB2(x-1),f(x)
#define FIBB4(x) FIBB3(x-1),f(x)
#define FIBB5(x) FIBB4(x-1),f(x)
#define FIBB6(x) FIBB5(x-1),f(x)
#define FIBB7(x) FIBB6(x-1),f(x)
#define FIBB8(x) FIBB7(x-1),f(x)
#define FIBB9(x) FIBB8(x-1),f(x)
#define FIBB10(x) FIBB9(x-1),f(x)
#define FIBB11(x) FIBB10(x-1),f(x)
#define FIBB12(x) FIBB11(x-1),f(x)
#define FIBB13(x) FIBB12(x-1),f(x)
#define FIBB14(x) FIBB13(x-1),f(x)
#define FIBB15(x) FIBB14(x-1),f(x)
#define FIBB16(x) FIBB15(x-1),f(x)
#define FIBB17(x) FIBB16(x-1),f(x)
#define FIBB18(x) FIBB17(x-1),f(x)
#define FIBB19(x) FIBB18(x-1),f(x)
#define FIBB20(x) FIBB19(x-1),f(x)
// ...
#define FIBB93(x) FIBB92(x-1),f(x)
//#define FIBB94(x) FIBB93(x-1),f(x) //unsigned long long overflow, can't calculate more
#define FIBB(x) {FIBB##x(x)}
constexpr unsigned long long fib[93] = FIBB(93);
int main()
{
// all possible fibbonacci numbers for unsigned long long implementation
for(int i=0; i<93; ++i)
std::cout << fib[i] << std::endl;
}
I think it's the only way for C++ built-in array.
Here's a C++14 solution (GCC >= 5.0.0, Clang >= 3.5.0) using a template argument for the length. You write an imperative loop (identical to your original post) in a constexpr function. Using a disassembler, you can see the sequence is embedded into the program as raw data, even with no optimizations (-O0).
#include <array>
#include <cstddef>
#include <iostream>
#include <type_traits>
#include <utility>
namespace {
// Create an std::array from a C array (internal) via an
// std::index_sequence.
template <typename T, typename TSequence> struct MakeArrayImpl;
template <typename T, std::size_t... TIndices>
struct MakeArrayImpl<T, std::index_sequence<TIndices...>> {
static constexpr std::array<T, sizeof...(TIndices)>
make_array(T values[sizeof...(TIndices)]) {
return std::array<T, sizeof...(TIndices)>{{values[TIndices]...}};
}
};
// Create an std::array from a C array.
template <typename T, std::size_t TLength>
constexpr std::array<T, TLength> make_array(T values[TLength]) {
return MakeArrayImpl<T, std::make_index_sequence<TLength>>::make_array(
values);
}
// Return an std::array of the first numbers in the Fibonacci sequence.
template <std::size_t TLength>
constexpr std::array<long long int, TLength> fibs() {
// Original algorithm.
long long int fib[TLength] = {0};
fib[0] = 1;
fib[1] = 1;
for (std::size_t i = 2; i < TLength; ++i) {
fib[i] = fib[i - 2] + fib[i - 1];
}
return make_array<long long int, TLength>(fib);
}
}
int main() {
// Original algorithm.
const int N = 92;
long long int fib[N] = {0};
fib[0] = 1;
fib[1] = 1;
for (int i = 2; i < N; ++i)
fib[i] = fib[i - 2] + fib[i - 1];
// Test constexpr algorithm against original algorithm.
static constexpr auto values = fibs<N>();
static_assert(values.size() == N, "Expected N values in Fibs");
for (int i = 0; i < N; ++i) {
if (fib[i] != values[i]) {
std::cerr << "Mismatch at index " << i << "\n";
std::cerr << "Expected: " << fib[i] << "\n";
std::cerr << "Actual : " << values[i] << "\n";
}
}
}
In the code sample you posted, there is a decent chance that the compiler may unroll the loop, or at least part of it, on its own, if -O3 optimizations are used. Playing around on godbolt, it appears that this doesn't happen at N=100 but does at N up to about 40. In this case it does happen at compile time, whether or not it is constexpr.
Which also points out -- on many machines, long long int is not large enough to hold the 100'th fibonacci number. Fibonacci numbers grow exponentially, you should expect the 100th number to require about 100 bits or so. Your code as written will exhibit undefined behavior due to integer overflow, on a typical machine.
Using a template you can do it like this:
// Fibonacci recurrence
template <long int n>
struct fib_pair {
typedef fib_pair<n-1> prev;
static constexpr long int fib_n = prev::fib_n_plus_one;
static constexpr long int fib_n_plus_one = prev::fib_n + prev::fib_n_plus_one;
};
template <>
struct fib_pair<0> {
static constexpr long int fib_n = 0;
static constexpr long int fib_n_plus_one = 1;
};
// List structure
template <long int ... > struct list {};
// Concat metafunction
template <typename A, typename B> struct concat;
template <long int... As, long int... Bs> struct concat<list<As...>, list<Bs...>> {
typedef list<As..., Bs...> type;
};
// Get a sequence from the fib_pairs
template <long int n>
struct fib_seq {
typedef typename fib_seq<n-1>::type prev;
typedef typename concat<prev, list<fib_pair<n>::fib_n>>::type type;
};
template <>
struct fib_seq<0> {
typedef list<0> type;
};
// Make an array from pack expansion
#include <array>
template <typename T> struct helper;
template <long int ... nums>
struct helper <list<nums...>> {
typedef std::array<const long int, sizeof...(nums)> array_type;
static constexpr array_type get_array() {
return {{ nums... }};
}
};
// Easy access
template <long int n>
constexpr std::array<const long int, n + 1> get_fib_array() {
return helper<typename fib_seq<n>::type>::get_array();
}
#include <iostream>
int main () {
for (const long int x : get_fib_array<15>()) {
std::cout << x << std::endl;
}
}
Here's a C++11 solution using C++14 library features [1] (GCC >= 4.9.0, Clang >= 3.5.0) using a template argument for the length. You write a loop using recursion. Using a disassembler, you can see the sequence is embedded into the program as raw data, even with no optimizations (-O0).
[1] std::index_sequence can be implemented yourself in C++11 if it is not available in your standard library.
#include <array>
#include <cstddef>
#include <iostream>
#include <type_traits>
#include <utility>
namespace {
// Create an std::array from a C array (internal) via an
// std::index_sequence.
template <typename T, typename TSequence> struct MakeArrayImpl;
template <typename T, std::size_t... TIndices>
struct MakeArrayImpl<T, std::index_sequence<TIndices...>> {
static constexpr std::array<T, sizeof...(TIndices)>
make_array(T values[sizeof...(TIndices)]) {
return std::array<T, sizeof...(TIndices)>{{values[TIndices]...}};
}
};
// Create an std::array from a C array.
template <typename T, std::size_t TLength>
constexpr std::array<T, TLength> make_array(T values[TLength]) {
return MakeArrayImpl<T, std::make_index_sequence<TLength>>::make_array(
values);
}
// Return an std::array of the first numbers in the Fibonacci sequence.
template <std::size_t TLength>
constexpr std::array<long long int, TLength> fibs() {
// Original algorithm.
long long int fib[TLength] = {0};
fib[0] = 1;
fib[1] = 1;
for (std::size_t i = 2; i < TLength; ++i) {
fib[i] = fib[i - 2] + fib[i - 1];
}
return make_array<long long int, TLength>(fib);
}
}
int main() {
// Original algorithm.
const int N = 92;
long long int fib[N] = {0};
fib[0] = 1;
fib[1] = 1;
for (int i = 2; i < N; ++i)
fib[i] = fib[i - 2] + fib[i - 1];
// Test constexpr algorithm against original algorithm.
static constexpr auto values = fibs<N>();
static_assert(values.size() == N, "Expected N values in Fibs");
for (int i = 0; i < N; ++i) {
if (fib[i] != values[i]) {
std::cerr << "Mismatch at index " << i << "\n";
std::cerr << "Expected: " << fib[i] << "\n";
std::cerr << "Actual : " << values[i] << "\n";
}
}
}
I tried to write my own function for this, but I get wrong result
#include <iostream>
using namespace std;
template<typename T>
int array_length(T v[]) {
return (sizeof v)/sizeof(T);
}
int main() {
int v[] = {1, 2, 3, 4};
cout << array_length(v) << endl;
return 0;
}
Something like this:
#include <cstddef> // for size_t
template< typename T, std::size_t N >
std::size_t length( const T (&)[N] )
{
return N;
}
Usage
int data[100];
std::cout << length(data) << "\n";
The length is supplied by the array. So try this:
template <typename T, std::size_t N> std::size_t length( T (&)[N] ) {
return N;
}
std::size_t is found in header <cstddef>. It is an unsigned integer type.