0

Apologies for the amateurish question - I'm new to c++ from python and am struggling to understand the way in which I include code from other files, and how that ties into static declarations and namespaces.

I have a file I'm using to try to compile and run a test using someone else's git repo.

My test file looks like this:

#include "omp/HandEvaluator.h"
#include <iostream>
using namespace omp;

int main()
{
    omp::HandEvaluator eval;
    Hand h = Hand::empty();
    h += Hand(51) + Hand(48) + Hand(0) + Hand(1) + Hand(2);
    std::cout << eval.evaluate(h) << std::endl;
}

The include of omp/HandEvaluator.h refers to this file in a directory within my project.

When I try to compile my code file, I get many 'undefined symbols' like this:

Undefined symbols for architecture x86_64:
  "omp::HandEvaluator::FLUSH_LOOKUP", referenced from:
      unsigned short omp::HandEvaluator::evaluate<true>(omp::Hand const&) const in example-a317b9.o

Looking at other answers for similar issues, I gather it often relates to declaration, but aren't these already defined in the omp namespace, which I bring in with using namespace omp?

omp/HandEvaluator.h is below:

#ifndef OMP_HAND_EVALUATOR_H
#define OMP_HAND_EVALUATOR_H

#include "Util.h"
#include "Constants.h"
#include "Hand.h"
#include <cstdint>
#include <cassert>

namespace omp {

// Evaluates hands with any number of cards up to 7.
class HandEvaluator
{
public:
    HandEvaluator();

    // Returns the rank of a hand as a 16-bit integer. Higher value is better. Can also rank hands with less than 5
    // cards. A missing card is considered the worst kicker, e.g. K < KQJT8 < A < AK < KKAQJ < AA < AA2 < AA4 < AA432.
    // Hand category can be extracted by dividing the value by 4096. 1=highcard, 2=pair, etc.
    template<bool tFlushPossible = true>
    OMP_FORCE_INLINE uint16_t evaluate(const Hand& hand) const
    {
        omp_assert(hand.count() <= 7 && hand.count() == bitCount(hand.mask()));
        if (!tFlushPossible || !hand.hasFlush()) {
            uint32_t key = hand.rankKey();
            return LOOKUP[perfHash(key)];
        } else {
            uint16_t flushKey = hand.flushKey();
            omp_assert(flushKey < FLUSH_LOOKUP_SIZE);
            return FLUSH_LOOKUP[flushKey];
        }
    }

private:
    static unsigned perfHash(unsigned key)
    {
        omp_assert(key <= MAX_KEY);
        return key + PERF_HASH_ROW_OFFSETS[key >> PERF_HASH_ROW_SHIFT];
    }

    static bool cardInit;
    static void initCardConstants();
    static void staticInit();
    static void calculatePerfectHashOffsets();
    static unsigned populateLookup(uint64_t rankCounts, unsigned ncards, unsigned handValue, unsigned endRank,
                                   unsigned maxPair, unsigned maxTrips, unsigned maxStraight, bool flush = false);
    static unsigned getKey(uint64_t rankCounts, bool flush);
    static unsigned getBiggestStraight(uint64_t rankCounts);
    static void outputTableStats(const char* name, const void* p, size_t elementSize, size_t count);

    // Rank multipliers for non-flush and flush hands.
    static const unsigned RANKS[RANK_COUNT];
    static const unsigned FLUSH_RANKS[RANK_COUNT];

    // Turn on to recalculate and output the offset array.
    static const bool RECALCULATE_PERF_HASH_OFFSETS = false;

    // Determines in how many rows the original lookup table is divided (2^shift). More rows means slightly smaller
    // lookup table but much bigger offset table.
    static const unsigned PERF_HASH_ROW_SHIFT = 12;
    static const unsigned PERF_HASH_COLUMN_MASK = (1 << PERF_HASH_ROW_SHIFT) - 1;

    // Minimum number of cards required for evaluating a hand. Can be set to higher value to decrease lookup
    // table size (requires hash recalculation).
    static const unsigned MIN_CARDS = 0;

    // Lookup tables
    static const unsigned MAX_KEY;
    static const size_t FLUSH_LOOKUP_SIZE = 8192;
    static uint16_t* ORIG_LOOKUP;
    static uint16_t LOOKUP[86547 + RECALCULATE_PERF_HASH_OFFSETS * 100000000];
    static uint16_t FLUSH_LOOKUP[FLUSH_LOOKUP_SIZE];
    static uint32_t PERF_HASH_ROW_OFFSETS[8191 + RECALCULATE_PERF_HASH_OFFSETS * 100000];
};

}

#endif // OMP_HAND_EVALUATOR_H

I've tried declaring omp::HandEvaluator::FLUSH_LOOKUP as per similar questions, but I'm really not sure how to proceed - anything to point me in the right direction or relevant areas to read myself to understand this better would be appreciated.

  • 2
    Can you show the command that you are compiling with? Since `FLUSH_LOOKUP` is static it is defined in C++ file. You need to make sure you compile and link that file. – 001 Oct 05 '18 at 14:16
  • How do you build your project and link `omp` library? See also: [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Yksisarvinen Oct 05 '18 at 14:17
  • ah ok - I didn't realise this. I'm only referencing my test file - g++ -std=c++14 -o test test.cpp – seymourgoestohollywood Oct 05 '18 at 14:21
  • @Yksisarvinen - thanks for this - will read through – seymourgoestohollywood Oct 05 '18 at 14:22

0 Answers0