Asher
Asher

Reputation: 1235

C++14 constexpr static const std::array initialization

This was much longer, but now that I found what was going on it was not helpful.

Short summary:

  1. Template with variable ints summing < 64.
  2. We want to know the # of ints + how many times the last int has to be repeated to reach a sum >= 64.
  3. We want to end up with a constexpr const static array std::array.

I was having linking errors without a declaration of the static member outside of the class. When present, Clang was segfaulting.

The problem ended up being that I had defined the function as

<BitBranch, numberOfBranches> 

but then the declaration had ended up using the numberOfBranches accessor method

<BitBranch, branchCount()>

A very silly mistake, but it wasn't obvious to me to track down.

I'll include my code as an example in case someone finds it helpful.

Working with C++14:

/* Using -std=c++1y */

#include <array>
#include <cmath>

template
<class          BitBranch,
 uint64_t...    BitLengths>
class BitBranchTree
{

Count How Many Bits are covered by Explicit Parameters in Pack

      template <typename ...Ints>
      constexpr static uint64_t countExplicitBits(
        uint64_t   bit_length,
        Ints...    bit_lengths ) 
      {
        return bit_length + countExplicitBits( bit_lengths... );
      }

      constexpr static uint64_t countExplicitBits( 
        uint64_t   bit_length ) 
      {
        return bit_length;
      }

Count How Many Bits Require Additional Implicit Parameters

      constexpr
      static

      uint64_t

      calculateImplicitBranches()
      {
        uint64_t remaining_bits            = 64 - explicitBitCount;
        uint64_t final_explicit_bit_length = explicitBranchLengths[ explicitBranchCount - 1 ];
        uint64_t smaller_final_length      = remaining_bits % final_explicit_bit_length;
        uint64_t remaining_full_branches   = remaining_bits / final_explicit_bit_length;
        uint64_t implicit_branch_count     = smaller_final_length ? remaining_full_branches + 1
                                                                  : remaining_full_branches;

        return implicit_branch_count;
      }

Initialize Desired Final Array

      template <uint64_t... Indexes>
      constexpr static std::array<BitBranch, sizeof...(Indexes)>
      initializeBranches(
        std::integer_sequence<uint64_t, Indexes...> )
      {
        return { initializeBranch( Indexes )... };
      }

Initialize Each Branch of Final Array

      constexpr static BitBranch
      initializeBranch(
        uint64_t index )
      {
        uint64_t bit_length = ( index < explicitBranchCount )
                              ? explicitBranchLengths[ index ]
                              : explicitBranchLengths[ explicitBranchCount - 1 ];

        return BitBranch( bit_length );
      }

Member Variables / Initialization

      constexpr static const uint64_t
      explicitBranchCount = sizeof...(BitLengths);

      constexpr static const uint64_t
      explicitBitCount = countExplicitBits( BitLengths... );

      constexpr static const uint64_t
      explicitBranchLengths[ explicitBranchCount ] = { BitLengths... };

      constexpr static const uint64_t
      implicitBranchCount = calculateImplicitBranches();

      static const uint64_t
      numberOfBranches = explicitBranchCount + implicitBranchCount;

      constexpr static const std::array <BitBranch, numberOfBranches>
      branches = initializeBranches( std::make_integer_sequence <uint64_t, numberOfBranches>{} );
};

Finally, Outside of the Class

    template
    <class          BitBranch,
     uint64_t...    BitLengths>

    constexpr
    const
    std::array
          <BitBranch,
           BitBranchTree<BitBranch, BitLengths...>::numberOfBranches>

    BitBranchTree<BitBranch, BitLengths...>::branches;

Examples of Usage

typedef
BitBranchTree<BitBranchMock, 4, 16, 7, 8, 5, 2, 8, 12, 2>
CompleteSpecification; // Results in Branches: 4, 16, 7, 8, 5, 2, 8, 12, 2

typedef
BitBranchTree<BitBranchMock, 4, 16>
PartialSpecification;  // Results in Branches: 4, 16, 16, 16, 12

Upvotes: 1

Views: 1758

Answers (1)

user657267
user657267

Reputation: 21038

You need to match the definition of BitBranchTree::branches with the declaration as follows

template
<class          BitBranch,
 uint64_t...    BitLengths>
constexpr const std::array <BitBranch, BitBranchTree<BitBranch, BitLengths...>::numberOfBranches>
BitBranchTree<BitBranch, BitLengths...>::branches;

You could also change the declaration to use branchCount(), the important thing is that they are identical.

Presumably clang 3.4 crashed instead of giving an error due to a compiler bug, your original code gives the following error on clang 3.5

test.cpp:199:42: error: redefinition of 'branches' with a different type: 'array<[...], BitBranchTree<BitBranch, BitLengths...>::branchCount()>' vs
      'const array<[...], numberOfBranches>'
BitBranchTree<BitBranch, BitLengths...>::branches;
                                         ^
test.cpp:181:7: note: previous definition is here
      branches = initializeBranches( std::make_integer_sequence <uint64_t, numberOfBranches>{} );

Upvotes: 2

Related Questions