0

I am writing a small toy project (a datastructure) where I have a collection of constants that I would like to bundle in an anonymous struct that lives in the main class. This class uses some of the constants to declare the size of static arrays. It looks somewhat like this:

template< class T, size_t K >
class Tree {
    static struct {
        size_t const min_keys{ K };
        size_t const max_keys{ 2*K };
        ...
    } const constants;
    ...
};

K is a template parameter, and all the members of the struct are const. However, the compiler (I am using g++ 5.1) complains when declaring an static array.

bpt.h:34:34: error: size of array is not an integral constant-expression
     T keys[constants.max_keys];

This confuses me – everything is const. I am merely trying to clean up my constants, bundling them like this seemed ideal and interesting. Using an enum class would be nice too, but as the class also needs to compare against those constants, is out of the question. Right now I am using an anonymous enum which does work, but this has stirred my curiosity.

Why is this? Is this a bad idea? I am very new to C++ – I would be thrilled to see alternatives.

7
  • 1
    Cannot reproduce -- get a better compiler? Commented Jul 18, 2015 at 17:58
  • Same here, what you've got compiles for me on MSVS2013. What are you using? Also, is there code where you create an instance that you're not showing here? Commented Jul 18, 2015 at 18:00
  • 1
    Note however that you will probably have to provide a definition for the static constant member at some point, and to do so, you may find it awkward to say its type if you don't give the type a name. Alternatively, make the static member constexpr, in which case you can use the member values as constant expressions, too. Commented Jul 18, 2015 at 18:01
  • @Kerrek SB: You are even trying to reproduce it. The point is in extra code T keys[constants.max_keys]; declaration. That's what you a have to compile. Commented Jul 18, 2015 at 18:01
  • 2
    @AnT: Use constexpr. And the OP's code doesn't contain the problematic example! Commented Jul 18, 2015 at 18:02

1 Answer 1

1

The following code works:

#include <cstddef>
#include <iostream>

template <typename T, std::size_t K>
struct Tree {
    static constexpr struct {
    //     ^^^^^^^^^
        std::size_t const min_keys{ K };
        std::size_t const max_keys{ 2*K };
    } constants {};
    //         ^^^
};

Example usage:

int main()
{
    int foo[Tree<int, 20>::constants.min_keys] = {1, 2};
}

The key point is to make Tree::constants a constexpr static data member, which means that its members are constant expressions that can be used as, say, array sizes. Note:

  • static constexpr members need initializers, hence the {} (or we could have put {K, 2 * K} here and left off the brace-or-equal initializers).

  • You don't need a definition for the static constexpr member as long as you don't odr-use it (e.g. don't try to compute &Tree<int, 3>::constants). This is convenient.

Sign up to request clarification or add additional context in comments.

1 Comment

@eudaemonia: No problem. I'd still consider it a bit bad for readability to not give the inner class a name, but it certainly works. If it solves your problem, go for it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.