2

I recently downloaded VS2015 and started tinkering around with new C++11 features. One of the features that was lacking in my game engine was a HashedString class. Since C++11 introduced constexpr, I thought a HashedString class would be a good place to start.

However, I have run into a road block with a compilation error. Whenever I try to invoke a constexpr member function from a constexpr constructor's member initializer list, the compiler complains that the member function call does not result in a constant expression. I even tried to simplify the HashString and HashStringDJB2Recursive calls to just return 0, yet, the same compile error still exists. If I remove the call to HashString, everything compiles just fine.

As far as I have researched, the member functions supplied below do not violate C++11 constexpr rules. It is possible I have missed or misunderstood something about the C++ constexpr rules. Any clarification as to why this does not compile would be much appreciated!

namespace CBConstants
{
   constexpr unsigned int HASHED_STRING_HASH_CONSTANT = 5381;
}


class HashedString
{
public:
    ~HashedString();

    explicit constexpr HashedString( const char* stringToHash ) noexcept
        : mStringHash( HashString( stringToHash ) ),
            mStringData( stringToHash )
    {

    }

    private:
    // DJB2 Hash documentation http://www.cse.yorku.ca/~oz/hash.html
    constexpr unsigned int HashedString::HashString( const char* stringToHash ) const noexcept
    {
        return ( ( !stringToHash ) ? 0 : HashStringDJB2Recursive( CBConstants::HASHED_STRING_HASH_CONSTANT, stringToHash ) );
    }


     constexpr unsigned int HashedString::HashStringDJB2Recursive( const unsigned int hashConstant, const char* stringToHash ) const noexcept
     {
        return ( !(*stringToHash) ? hashConstant : HashStringDJB2Recursive(((hashConstant << 5) + hashConstant) + (*stringToHash), stringToHash + 1 ) );
     }

    unsigned int        mStringHash;
    const char*         mStringData;

};

The compile error:

Error C2134 'HashedString::HashString': call does not result in a constant expression hashedstring.h 17 note: failure was caused by call of undefined function or one not declared 'constexpr'.

Paul Renton
  • 2,652
  • 6
  • 25
  • 38

1 Answers1

2

Your class is not a literal because you have a non-trivial destructor.

According to the C++ standard

12.4/5 A destructor is trivial if it is not user-provided and if:

— the destructor is not virtual,

— all of the direct base classes of its class have trivial destructors, and

— for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.

Otherwise, the destructor is non-trivial.

In your case you declare the destructor, so the destructor is non trivial. If you do

~HashedString() = default;

or even don't declare it, the code should compile.

Live example on Coliru

EDIT

VC++ seems to care about the order of definition of your functions. Moving them above the constructor will make the code compilable (although this is not mandated by the C++ standard).

Live example on rextester VC++

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • Thanks for the reply. I tried both removing the destructor and declaring the destructor to be default. Doing both still resulted in the same compile error. – Paul Renton Nov 25 '15 at 02:16
  • @PaulRenton Did you try the exact example that I linked? If it doesn't work, then you probably bumped into a VC++ bug. VC++ doesn't fully support C++11. The code compiles with both gcc and clang. – vsoftco Nov 25 '15 at 02:17
  • Copied and pasted the code example. Same error. I did notice that there is a clarifying statement on the error: note: failure was caused by call of undefined function or one not declared 'constexpr'. Maybe this is a VC++ bug :( – Paul Renton Nov 25 '15 at 02:19
  • According to [this link](https://msdn.microsoft.com/en-us/library/hh567368.aspx) VS2015 seems to fully support `constexpr`, although if you said the code linked doesn't compile, then it probably doesn't. Did you try something as simple as [this](http://coliru.stacked-crooked.com/a/bd37e06e7f97e0f0)? – vsoftco Nov 25 '15 at 02:24
  • Yes that simple example compiles just fine. – Paul Renton Nov 25 '15 at 02:28
  • @PaulRenton Just try adding one member function and see exactly where and when the error occurs. Also make absolutely sure you don't have a user-provided destructor. Your code is otherwise standard compliant. You don't even use [extended constexpr](https://isocpp.org/wiki/faq/cpp14-language#extended-constexpr) C++14 features. – vsoftco Nov 25 '15 at 02:33
  • 1
    @PaulRenton I figured out what happens in VC++, although most likely it's a bug. See the edit. – vsoftco Nov 25 '15 at 02:46
  • Never would have guessed order would matter here. Good catch. – Paul Renton Nov 25 '15 at 02:48
  • @PaulRenton It shouldn't, because inside a class all member functions are considered visible. So I think it's a VC++ bug, you should probably report it (if it's not already). See e.g. [this](http://stackoverflow.com/q/32685319/3093378) and the corresponding answer. – vsoftco Nov 25 '15 at 02:49
  • The compiler doesn't *assume* it's a non-trivial destructor, the destructor *is* non-trivial since it's user-provided: "A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration." – Casey Nov 25 '15 at 05:28
  • @Casey Agree, I changed the wording. – vsoftco Nov 25 '15 at 05:33