Compile time hash - confusion on template deduction order - c++11

I have found this piece of code in other topic
template<size_t N, size_t I = 0>
struct hash_calc
{
static constexpr size_t apply(const char(&s)[N])
{
return (hash_calc < N, I + 1 >::apply(s) ^ s[I]) * 16777619u;
};
};
template<size_t N>
struct hash_calc<N, N>
{
static constexpr size_t apply(const char(&s)[N])
{
return 2166136261u;
};
};
template<size_t N>
constexpr size_t hash(const char(&s)[N])
{
return hash_calc<N>::apply(s);
}
First of all, I am totally confused why it does not end being an infinite recursive call? From what I understand, first hash_calc<N, I> is always going to call itself, what causes it to break at the hash_calc<N, N> when I reaches N? The template instantiation for hash_calc<N, I> does not fail when N == I.
Second - i tried to copy paste the hash_calc<N, N> struct over hash_calc<N, I> which causes compile error error: 'hash_calc' is not a class template struct hash_calc<N, N>. Why is that?!
Edit:
The modified code below does not compile under msvc nor gcc. I have just put one template over other. What happened?
template<size_t N>
struct hash_calc<N, N>
{
static constexpr size_t apply(const char(&s)[N])
{
return 2166136261u;
};
};
template<size_t N, size_t I = 0>
struct hash_calc
{
static constexpr size_t apply(const char(&s)[N])
{
return (hash_calc < N, I + 1 >::apply(s) ^ s[I]) * 16777619u;
};
};
template<size_t N>
constexpr size_t hashq(const char(&s)[N])
{
return hash_calc<N>::apply(s);
}

I am totally confused why it does not end being an infinite recursive call?
So let's look at it, step by step.
hashq<N>(const char(&s)[N]) calls hash_calc<N>::apply(s);.
That's:
template<size_t N, size_t I = 0>
struct hash_calc
{
static constexpr size_t apply(const char(&s)[N])
{
return (hash_calc < N, I + 1 >::apply(s) ^ s[I]) * 16777619u;
};
};
with I==0.
Now hash_calc < N, I + 1 >::apply(s) is called, with I==1, this goes on until I==N. That's when
template<size_t N>
struct hash_calc<N, N>
{
static constexpr size_t apply(const char(&s)[N])
{
return 2166136261u;
};
};
is called. And the recursion ends.
Why is that?!
template<size_t N, size_t I = 0>
struct hash_calc
{
static constexpr size_t apply(const char(&s)[N])
{
return (hash_calc < N, I + 1 >::apply(s) ^ s[I]) * 16777619u;
};
};
is the more general case, it handles any pair of <N,I>, whereas
template<size_t N>
struct hash_calc<N, N>
{
static constexpr size_t apply(const char(&s)[N])
{
return 2166136261u;
};
};
is its specialisation, it can only handle the case of <N,N>.
The compiler first needs the general case and then the specialiation.

Related

Passing const reference pointer fails to match method signature

The following code passes a const pointer reference to a size() helper function. It only works if I remove the const or the & reference operator from the helper function.
#include <iostream>
using namespace std;
template <typename T>
class Test {
public:
Test();
int size();
void insert(T);
private:
struct Node {
T value;
Node* left;
Node* right;
};
Node* root;
int size(const Node*& node);
};
template <typename T>
Test<T>::Test() { root = nullptr;}
template <typename T>
int Test<T>::size() {return size(root);}
template <typename T>
int Test<T>::size(const Node*& node) {
if (node != nullptr)
return 1 + size(node->left) + size(node->right);
return 0;
}
int main() {
Test<int> t;
cout << "Size: " << t.size() << endl;
}
I get the following compiler errors when I compile this code as C++11:
main.cpp:31:11: error: no matching member function for call to 'size'
return size(root);
^~~~
main.cpp:43:26: note: in instantiation of member function 'Test<int>::size' requested here
cout << "Size: " << t.size() << endl;
^
main.cpp:21:11: note: candidate function not viable: no known conversion from 'Test<int>::Node *' to 'const Test<int>::Node *&' for 1st argument
int size(const Node*& node);
^
main.cpp:10:11: note: candidate function not viable: requires 0 arguments, but 1 was provided
int size();
^
1 error generated.
However, if I simply remove the const or the reference operator (&) from the helper function that size() calls, it compiles and runs exactly as expected.
In other words, either of the following works:
int size(Node*& node);
template <typename T> int Test<T>::size(Node*& node)
int size(const Node* node);
template <typename T> int Test<T>::size(const Node* node)
But this does not:
int size(const Node*& node);
template <typename T> int Test<T>::size(const Node*& node)
The declaration and implementation seem identical in all three cases, so I am having a hard time figuring out why the case with the const reference fails.
If it were legal to pass a pointer to non-const object where a reference to pointer to const object is expected, then it would be possible to violate const correctness. Consider:
const int c = 42;
void f(const int*& p) {
// Make p point to c
p = &c;
}
int* q;
f(q); // hypothetical, doesn't compile
// Now q points to c
*q = 84; // oops, modifying a const object

clang - how to declare a static const int in header file?

Given the following template in a header file, and a couple of specializations:
template<typename> class A {
static const int value;
};
template<> const int A<int>::value = 1;
template<> const int A<long>::value = 2;
and building with clang-5, it results in errors for each source unit that included the file, all complaining about multiple definitions for A<int>::value and A<long>::value.
At first, I thought that maybe the template specializations needed to be put in a specific translation unit, but on checking the spec, this apparently should be allowed, because the value is a constant integer.
Am I doing something else wrong?
EDIT: if I move the definition into a single translation unit, then I can no longer use the value of A<T>::value in the context of a const int (eg, where its value is being used to calculate the value of another const assignment) , so the value really needs to be in a header.
In c++11 you maybe can go that way:
template<typename> class B {
public:
static const int value = 1;
};
template<> class B<long> {
public:
static const int value = 2;
};
template<typename T> const int B<T>::value;
If you only want to specialize the value var, you can use CRTP for that.
From C++17 you can make your definition inline:
template<> inline const int A<int>::value = 1;
template<> inline const int A<long>::value = 2;
Also from c++17 you can remove the 'template const int B::value;' for constexpr:
template<typename> class C {
public:
static constexpr int value = 1;
};
template<> class C<long> {
public:
static constexpr int value = 2;
};
// no need anymore for: template<typename T> const int C<T>::value;
And another solution for c++11 can be to use a inline method instead of inline vars which are allowed from c++17:
template<typename T> class D {
public:
static constexpr int GetVal() { return 0; }
static const int value = GetVal();
};
template <> inline constexpr int D<int>::GetVal() { return 1; }
template <> inline constexpr int D<long>::GetVal() { return 2; }
template< typename T>
const int D<T>::value;
In addition to your last edit:
To use your values also in other dependent definitions it seems to be the most readable version if you use the inline constexpr methods.
Edit: "Special" version for clang, because as OP tells us, clang complains with "specialization happening after instantiation". I don't know if clang or gcc is wrong in that place...
template<typename T> class D {
public:
static constexpr int GetVal();
static const int value;
};
template <> inline constexpr int D<int>::GetVal() { return 1; }
template <> inline constexpr int D<long>::GetVal() { return 2; }
template <typename T> const int D<T>::value = D<T>::GetVal();
int main()
{
std::cout << D<int>::value << std::endl;
std::cout << D<long>::value << std::endl;
}
I told already that CRTP is possible if not the complete class should be redefined. I checked the code on clang and it compiles without any warning or error, because OP comments that he did not understand how to use it:
template<typename> class E_Impl {
public:
static const int value = 1;
};
template<> class E_Impl<long> {
public:
static const int value = 2;
};
template<typename T> const int E_Impl<T>::value;
template < typename T>
class E : public E_Impl<T>
{
// rest of class definition goes here and must not specialized
// and the values can be used here!
public:
void Check()
{
std::cout << this->value << std::endl;
}
};
int main()
{
E<long>().Check();
std::cout << E<long>::value << std::endl;
E<int>().Check();
std::cout << E<int>::value << std::endl;
}

Extract numeric parameters from template

I have following struct:
template <size_t INDEX_SIZE, size_t GENERATION_SIZE>
struct Handle
{
uint32_t index : INDEX_SIZE;
uint32_t generation : GENERATION_SIZE;
};
In code I declare a lot of type aliases like this:
using Object1Handle = Handle<12, 16>;
using Object2Handle = Handle<12, 16>;
...
I would like to have possibility to extract INDEX_SIZE and GENERATION_SIZE from alias. It can be macro, meta-template or function. For example:
constexpr size_t indexSize = ExtractIndexSize<Object1Handle>::IndexSize;
Is it possible?
Yes, that is possible. Using specialization:
template<class HandleInst>
struct ExtractIndexSize;
template<size_t index_size_, size_t generation_size_>
struct ExtractIndexSize<
Handle<index_size_, generation_size_>
> {
static constexpr size_t index_size = index_size_;
static constexpr size_t generation_size = generation_size_;
};
However, in this simple example (as also pointed out in the comments to your question) the static constexpr size_t could also be moved to Handle.
An alternative yielding "getter-like" syntax and fewer restrictions is
template<class HandleInst>
struct ExtractIndexSize;
template<size_t index_size_, size_t generation_size_>
struct ExtractIndexSize<
Handle<index_size_, generation_size_>
> {
static constexpr size_t index_size() { return index_size_; }
static constexpr size_t generation_size() { return generation_size_; }
};

How to make msvc 14 evaluate my constexpr at compile time

I am experimenting with c++ constexpr. I am implementing a HashedString class using FNV-1a hash.
Everything seems fine except that visual studio 2015 update 3 doesn't seem to evaluate the constexpr at compile time.
I added a static_assert and it shows no error, but in my test's disassembly it is clear that there is an explicit call to the constexpr function instead of the precomputed value.
I also tried with g++ and clang and they both are able to evaluate the constexpr at compile time.
Here is my test code:
#include <cstdint>
#include <cstddef>
#include <string>
class HashedString {
public:
//value working only for a 32bit hash
constexpr static size_t defaultOffset = 2166136261u;
constexpr static size_t prime = 16777619u;
/**
* Compute the hash of a string at compile time using FNV-1a hash
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80 %93Vo_hash_function
*/
template<std::size_t N>
constexpr HashedString(const char(&a)[N]) noexcept
: mHash(hash(a))
#if defined(_DEBUG)
, mString(a)
#endif
{
}
explicit constexpr HashedString(size_t h) noexcept : mHash(h) {}
constexpr static size_t hash(const char *const aString, const uint32_t val = defaultOffset) noexcept
{
return (aString[0] == '\0') ? val : hash(&aString[1], (val ^ uint32_t(aString[0])) * prime);
}
constexpr bool operator==(const HashedString & hs) const { return mHash == hs.mHash; }
constexpr bool operator==(const size_t & h) const { return mHash == h; }
constexpr bool operator!=(const HashedString & hs) const { return mHash != hs.mHash; }
constexpr bool operator!=(const size_t & h) const { return mHash != h; }
constexpr bool operator<(const HashedString & hs) const { return mHash < hs.mHash; }
private:
const size_t mHash = 0;
#if defined(_DEBUG)
const char* mString = nullptr;
#endif
};
static_assert(HashedString("FNV Hash Test") == 0xF38B3DB9, "HashedString of 'FNV Hash Test' shoulb be equal to 0xF38B3DB9");
int main(int , char**) {
constexpr HashedString hs("FNV Hash Test");
return hs == 0xF38B3DB9;
}
So my question is: Is there a way to make visual studio compute my constexpr at compile time?
Changing main to:
constexpr auto hash = HashedString::hash("FNV Hash Test");
return hash == 0xF38B3DB9;
or
constexpr HashedString hs("FNV Hash Test");
constexpr auto answer = hs == 0xF38B3DB9;
return answer;
will cause the hash to be computed at compile time. The way your code was there was no demand on the compiler to compute the hash at compile-time. By requiring the compiler to initialize a constexpr variable, it is forced to compute the value at compile-time. Which reduced main's code to:
mov eax,1
ret
Booyah! for VS2015's SSA optimizations.

N-dimensional tensor based on std::vector

I want to define n-dimensional data structure using std::vector. I have a problem with definition of operator(). Lets have a look at a sample 2D structure
class my_data {
public:
my_data (size_t N, size_t M) : tab(N*M), _N(N), _M(M) {}
const double& operator() (size_t i, size_t j) const {
return tab.at(i * M + j);
}
double& operator() (size_t i, size_t j) {
return tab.at(i * M + j);
}
private:
std::vector<double> tab;
size_t _N;
size_t _M;
};
I would like to define such a structures for any dimension using templates , but I don't know if it is possible. So basically what I would like to have is something like that
my_data<4> vec (1,2,3,4);
defines 4D 'tensor' with sizes 1,2,3,4 (number of all elements 1*2*3*4). You can now access and change values by typing
vec (0,0,0,0) = 2.0;
The below solution uses some of the C++14 and C++1z features, but they can be easily ported to C++11:
#include <vector>
#include <utility>
#include <array>
#include <cstddef>
namespace detail
{
template <typename T, typename S>
class my_data;
template <typename T, std::size_t... Is>
class my_data<T, std::index_sequence<Is...>>
{
public:
my_data(decltype(Is)... size)
: t((size * ...)), s{{ size... }}
{}
T& operator()(decltype(Is)... i)
{
return t.at(index({{ i... }}));
}
const T& operator()(decltype(Is)... i) const
{
return t.at(index({{ i... }}));
}
private:
std::size_t index(const std::array<std::size_t, sizeof...(Is)>& a) const
{
std::size_t ind = a[0];
for (std::size_t i = 1; i < a.size(); ++i)
{
ind = ind * s[i] + a[i];
}
return ind;
}
std::vector<T> t;
const std::array<std::size_t, sizeof...(Is)> s;
};
}
template <typename T, std::size_t N>
using my_data = detail::my_data<T, std::make_index_sequence<N>>;
Test:
int main()
{
my_data<double, 4> vec(1,2,3,4);
vec(0,0,0,0) = 2.0;
}
DEMO
DEMO (C++11)

Resources