1
votes

I have this class encrypted_string, which should encrypt strings at compile time. The issue I'm having is that I can't call the 'encrypt' member function in the constructor, but if I place the encryption in the constructor itself it works.

template<typename I>
class encrypted_string;

template<size_t... I>
class encrypted_string<std::index_sequence<I...>>
{
 private:
  std::array<char, sizeof...(I)> buf;

  constexpr char encrypt(char c) const { return c ^ 0x41; }

 public:
  constexpr encrypted_string(const char* str)
  : buf { (str[I] ^ 0x41)... } { } // Works
  //: buf { this->encrypt(str[I])... } { } // Error
};

#define enc(str) encrypted_string<std::make_index_sequence<sizeof(str)>>(str)

int main()
{
  // Ensures compile time evaluation
  constexpr auto s = enc("Test");

  return 0;
}

I'm compiling with 'g++ encrypted_string.cpp -std=c++14 -o encrypted_string' and my gcc version is 4.9.2.

Error I'm getting doesn't tell me much:

encrypted_string.cpp:17:13: note: ‘constexpr encrypted_string<std::integer_sequence<long unsigned int, _Idx ...> >::encrypted_string(const char*) [with long unsigned int ...I = {0ul, 1ul, 2ul, 3ul, 4ul}]’ is not usable as a constexpr function because:
constexpr encrypted_string(const char* str) : buf { this->encrypt(str[I])... } { }

Am I doing something wrong, or is it just not possible to call constexpr functions in constexpr constructor? From what I understood about the constexpr constructors it should be possible.

1
A constexpr is evaluated at compile time, so I guess invoking methods which are part of an instance of a class is not properly a valid request. I'm not sure about that, but it makes sense at least for me. - skypjack
Works fine in gcc 5.1 - user657267
The C++14 relaxed constant expressions are implemented in gcc >= 5, see gcc.gnu.org/projects/cxx1y.html With the C++11 rules, may not have any code within the constructor body (only typedefs, static asserts etc., no potential run-time code). - dyp
Make member function static or not member. - Tomilov Anatoliy
Thank you for the answers, I was able to compile it on gcc 4.9 by changing the encrypt function to staticas Orient pointed out. I updated to gcc 5.1 and now it works as I expected it to work without any modifications. - Freszone

1 Answers

2
votes

According to https://gcc.gnu.org/projects/cxx1y.html, C++14 constexpr support is not implemented until GCC 5.

As a result, GCC 4.9.2, even with -std=c++14, only supports C++11 constexprs which comprise a single statement that produces a return value. MSVC 2015 RC has the same limitation.

constexpr even(int n) { return (n & 1) == 0; } // valid c++11/14
constexpr even(int n) { return (n & 1) ? true : false; } // valid c++11/14
constexpr even(int n) { // valid c++14, not valid c++11
    if ((n & 1) == 0)
        return true;
    return false;
}