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.
Related
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
I am trying to make compile time checks over the format of the printf. Here is the code.
#include <type_traits>
#include <iostream>
template <typename CHAR, typename ...ARGS>
constexpr size_t trace_cond(CHAR fmt, ARGS&&... args) {
//always needs to pass
return 1;
}
template <size_t N, typename ...ARGS>
constexpr size_t trace_cond(const char (&fmt)[N], ARGS&&... args) {
//return parse(fmt) == args;
return sizeof...(args) != 0;
}
#define TRACE(fmt, ...) { \
static_assert(trace_cond(fmt, __VA_ARGS__), "Wrong ARGS"); \
printf(fmt, ##__VA_ARGS__); \
}
int main(int argc, char* argv[]) {
//working fine
TRACE("%d %d\n", 2, 3);
const char* format = "%d %d\n";
//error
TRACE(format, 2, 3);
}
So when the format is known at compile time I want to have a check(using static_assert) and if it is not known then the check should be not called or always to pass
Obs:
Currently the code is not compiling because const char *format is not declared constexpr
The main should not be change because TRACE macro is used in a large codebase but changes to TRACE are more than welcome
So my question is:
Is there a way to skip static_assert or make it pass when fmt type is const char *
I think you can do what you want by moving the static_assert to the trace_cond
#include <type_traits>
#include <iostream>
template <size_t C, typename CHAR>
size_t trace_cond(CHAR fmt) {
//always needs to pass
return 1;
}
template <typename ...ARGS>
constexpr size_t count_args(ARGS&&... args) {
return sizeof...(args);
}
template <size_t C, size_t N>
constexpr size_t trace_cond(const char (&fmt)[N]) {
// TODO, parse fmt and do the needed checks
static_assert(C == 3, "");
return 1;
}
#define TRACE(fmt, ...) { \
trace_cond<count_args(__VA_ARGS__)>(fmt); \
printf(fmt, ##__VA_ARGS__); \
}
int main(int argc, char* argv[]) {
// Static check - hard coded to check for 3 arguments
TRACE("%d %d %d\n", 2, 3, 4);
const char* format = "%d %d\n";
// No checks performed
TRACE(format, 2, 3);
}
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;
}
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.
I'm trying to make C-string size calculation at compile time, using code like this:
#include <stdio.h>
#include <stdint.h>
class StringRef
{
public:
template<int N>
constexpr StringRef(const char (&str)[N])
: m_ptr(str), m_size(uint32_t(N-1)) {}
constexpr const char *constData() const
{ return m_ptr; }
private:
const char *m_ptr;
uint32_t m_size;
};
struct S
{
StringRef str;
};
constexpr static const struct S list[] =
{
"str",
};
int main()
{
printf("%s\n", list[0].str.constData());
return 0;
}
In clang-3.7 everything is fine, but in GCC 4.9.3-5.3 I get:
error: could not convert '(const char*)"str"' from 'const char*' to
'StringRef'
It can be fixed by adding explicit braces:
constexpr static const struct S list[] =
{{
{ "str" },
}};
But code became ugly and, still, clang somehow understand it correctly.
How can I make gcc understand array initialization without explicit braces?