2

I have a HashTable< Customer > as a member in another class.

The constructor for HashTable< T > takes an int value in order to determine the size of the HashTable's array.

HashTable(int numItems) { ... } //constructor

The following declaration

HashTable<Customer> customers(10000); //doesn't call constructor???

receives the error "expected a type specifier" underneath the 10000. When I remove the 10000, I receive the error "Function definition for customers not found." This leads me to believe that the compiler is treating my object declaration as a function declaration.

When I declare my HashTable using dynamic allocation,

HashTable<Customer> * customers = new HashTable<Customer>(10000); //works

there is no confusion with the compiler.

Why does the dynamic allocation work, but not the other?

Edit: Here is a minimal code that has the same issue stated above.

#ifndef _BUSINESS_LOGIC
#define _BUSINESS_LOGIC

#include "HashTable.h"

class BusinessLogic
{
public:
    BusinessLogic();
    ~BusinessLogic();
    void start(); 

private:
    HashTable<int> * custom = new HashTable<int>(10000); //works
    HashTable<int> customers(10000); //error
};

#endif


#ifndef _HASH_TABLE
#define _HASH_TABLE

template<class T>
class HashTable
{
public:
    HashTable(int numItems) {
        if (numItems <= 0) {
            throw std::invalid_argument("Invalid HashTable size");
        }
        currItems = 0;

        //B must be the next prime after 2 * numItems
        B = numItems;
    }

    ~HashTable() {
    }


private:
    int B; //size of itemArray
};

#endif
shtuken
  • 171
  • 1
  • 9
  • 2
    Is the declaration of `customers` within a class? – 1201ProgramAlarm Dec 13 '16 at 05:32
  • It's difficult to tell what's wrong with bits and pieces of code. Please post a [mcve]. – R Sahu Dec 13 '16 at 05:34
  • http://stackoverflow.com/questions/31574575/how-is-this-a-most-vexing-parse – Retired Ninja Dec 13 '16 at 05:42
  • @RetiredNinja, the most vexing parse doesn't apply when the argument is a number such as the one being used by the OP. – R Sahu Dec 13 '16 at 05:48
  • It's partly because `HashTable customers(int 10000);` could be interpreted as a function declaration, and the compiler thinks you've forgotten the "int" part. See https://stackoverflow.com/questions/180172/default-constructor-with-empty-brackets – Zexus Dec 13 '16 at 06:02
  • I think you're confusing member initialization (which belongs in the member initializer list of a constructor) vs. a [*default member initializer*](http://en.cppreference.com/w/cpp/language/data_members#Member_initialization), which you can [read about **here**](https://stackoverflow.com/questions/36600187/whats-the-differences-between-member-initializer-list-and-default-member-initia). The latter requires the `=` – WhozCraig Dec 13 '16 at 06:07
  • Shouldn't the `10000` make the compiler realize it is an instantiation? Does `(int 10000)` even have a meaning as a parameter declaration? @Zexus, the link you provided says `MyObject object(blah); // ok`, which is what I did, is it not? – shtuken Dec 13 '16 at 06:07
  • 1
    I'm wondering if the compiler is smart enough to realize that 10000 couldn't be a variable name (perhaps if you do change it to `int 10000` and then recompile it'll complain about using a number as a variable). Have you tried `HashTable customers = HashTable (10000); ` ? – Zexus Dec 13 '16 at 06:09
  • 1
    @Zexus: I doubt any compiler would ever think that. – Benjamin Lindley Dec 13 '16 at 06:10
  • @Zexus, `HashTable customers = HashTable(10000);` works! But I still don't understand why `HashTable customers(10000);` does not. It does not appear to be a vexing case because I am not using empty parentheses. I am using Visual Studio in case that matters. – shtuken Dec 13 '16 at 06:13
  • The compiler is considering this line as the function 'customers' declaration that returns 'HashTable ' – Ignat Dec 13 '16 at 06:17
  • 2
    @Ignat: No, it isn't. That could not possibly be seen as a function declaration. – Benjamin Lindley Dec 13 '16 at 06:18
  • 1
    @shtuken: In this particular context the opening `(` invariably drives the parser into the "function declaration" branch of the grammar, making the parser to expect a parameter declaration next. But once the parser sees that `10000` the parsing immediately fails, since `10000` cannot be a parameter declaration. That's all there is to it. – AnT stands with Russia Dec 13 '16 at 06:32
  • @AnT, thanks for the explanation! – shtuken Dec 13 '16 at 06:56
  • This isn't the problem, but names that begin with an underscore followed by a capital letter (`_BUSINESS_LOGIC`) and names that contain two consecutive underscores are reserved for use by the implementation. Don't use them in your code. – Pete Becker Dec 13 '16 at 14:55

2 Answers2

7

You are not allowed to use () initializer syntax when supplying initializers for class members directly in class definition. It requires either = syntax of {} -enclosed initializer. In your case it would be either

HashTable<int> customers{10000};

or

HashTable<int> customers = 10000;

or, if you wish

HashTable<int> customers = { 10000 };

The last two versions work because your HashTable specialization provides an appropriate conversion constructor. If that constructor were declared explicit, you'd have to use

HashTable<int> customers = HashTable<int>(10000); // or `= HashTable<int>{10000}`

in place of the second and/or third variant.

The initializer you are trying to use is actually officially referred to as brace-or-equal-initializer. The name suggests the proper variants of the syntax.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
3

You can't provide a default member initializer for a member variable that way. You can go with either

HashTable<Customer> customers = HashTable<Customer>(1000);

or

HashTable<Customer> customers {1000};

or directly in the constructor

BusinessLogic::BusinessLogic(): customers(1000) { }
1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56