3

I'm trying to understand the code:

#include <iostream>
#include <stdexcept>

// constexpr functions use recursion rather than iteration
constexpr int factorial(int n)
{
    return n <= 1 ? 1 : (n * factorial(n-1));
}

// literal class
class conststr {
    const char * p;
    std::size_t sz;
 public:
    template<std::size_t N>
    constexpr conststr(const char(&a)[N]) : p(a), sz(N-1) {}
    // constexpr functions signal errors by throwing exceptions from operator ?:
    constexpr char operator[](std::size_t n) const {
        return n < sz ? p[n] : throw std::out_of_range("");
    }
    constexpr std::size_t size() const { return sz; }
};

constexpr std::size_t countlower(conststr s, std::size_t n = 0,
                                             std::size_t c = 0) {
    return n == s.size() ? c :
           s[n] >= 'a' && s[n] <= 'z' ? countlower(s, n+1, c+1) :
           countlower(s, n+1, c);
}

// output function that requires a compile-time constant, for testing
template<int n> struct constN {
    constN() { std::cout << n << '\n'; }
};

int main()
{
    std::cout << "4! = " ;
    constN<factorial(4)> out1; // computed at compile time

    volatile int k = 8; // disallow optimization using volatile
    std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time

    std::cout << "Number of lowercase letters in \"Hello, world!\" is ";
    constN<countlower("Hello, world!")> out2; // implicitly converted to conststr
}

What is the parameter

const char(&a)[N]

? I don't understand it.. seems like a reference to an array.. and what's the point in passing it to a constexpr constructor?

Cole Tobin
  • 9,206
  • 15
  • 49
  • 74
Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • Yes, it is a reference to an array of fixed size. And because its size is defined by a template, it has the result of defining a (constexpr) constructor for each size of array that you might pass (with the end result that `sz` is set to the constant size of the array you passed). So that's fine, but whether `constexpr` is actually *valid* for constructors is something I'm not sure about. – Dave Jun 08 '13 at 22:41
  • probably duplicate: http://stackoverflow.com/questions/6376000/how-does-this-array-size-template-work – cxyzs7 Jun 08 '13 at 22:44
  • OK, some quick searches tell me that `constexpr` constructors are indeed valid. In effect they allow the constructor to be called at compile time, leaving just something which behaves like `thing a={0,1,2}` behind, pretty much as you'd expect. – Dave Jun 08 '13 at 22:44

2 Answers2

5

The parameter const char(&a)[N] is a reference to an array.

The point of it is that it allows the compiler to deduce the length of the array. Without the reference, const char a[N] as parameter would be equivalent to const char* a which doesn't allow the template parameter N to be deduced.

celtschk
  • 19,311
  • 3
  • 39
  • 64
  • 1
    That is not the only point. The array is immutable. Plain `char(&a)[N]` wouldn't do here. – juanchopanza Jun 08 '13 at 22:46
  • Nor would `char* a`. But that's an orthogonal issue, and there's no indication that David Kermin had any problems with the `const`. – celtschk Jun 08 '13 at 22:48
  • It is not an orthogonal issue. The `constexprs` wouldn't work with a mutable, fixed size array. – juanchopanza Jun 08 '13 at 22:49
  • The deduction of `N` is orthogonal to the whole thing being `constexpr`. It would work exactly the same way on a non-`constexpr` template. – celtschk Jun 08 '13 at 22:50
2

This is (along with the template<std::size_t N> part), a way to get the size of a constant string, so you can do:

conststr hello("Hello, World!"); 

and later:

size_t s = hello.size(); 
Mats Petersson
  • 126,704
  • 14
  • 140
  • 227