error: request for member '..' in '..' which is of non-class type
Asked Answered
T

9

559

I have a class with two constructors, one that takes no arguments and one that takes one argument.

Creating objects using the constructor that takes one argument works as expected. However, if I create objects using the constructor that takes no arguments, I get an error.

For instance, if I compile this code (using g++ 4.0.1)...

class Foo
{
  public:
    Foo() {};
    Foo(int a) {};
    void bar() {};
};

int main()
{
  // this works...
  Foo foo1(1);
  foo1.bar();

  // this does not...
  Foo foo2();
  foo2.bar();

  return 0;
}

... I get the following error:

nonclass.cpp: In function ‘int main(int, const char**)’:
nonclass.cpp:17: error: request for member ‘bar’ in ‘foo2’, which is of non-class type ‘Foo ()()’

Why is this, and how do I make it work?

Tapetum answered 18/5, 2009 at 12:38 Comment(1)
B
840
Foo foo2();

change to

Foo foo2;

You get the error because compiler thinks of

Foo foo2()

as of function declaration with name 'foo2' and the return type 'Foo'.

But in that case If we change to Foo foo2 , the compiler might show the error " call of overloaded ‘Foo()’ is ambiguous".

Bismuthous answered 18/5, 2009 at 12:41 Comment(5)
I don't understand why the compiler thinks : Foo foo2() as of function declaration, inside the main function.Cynar
Apparently I've landed on this answer before since I can not upvote it again! Here is a textual 2nd upvote... and a 2nd thanks!Hardej
Parameterless function declaration should have mandated "void" parameter so that this usage would have been allowed from consistency point of view. If I am not mistaken, K&R C had mandatory usage of term void.Platto
@Rajesh: A void parameter list is not mandatory, it just means something different (zero parameters) from an empty parameter list (unspecified parameters).Gamekeeper
this is another good reason to switch to uniform {} initialization syntax introduces in c++11Scarrow
M
42

Just for the record..

It is actually not a solution to your code, but I had the same error message when incorrectly accessing the method of a class instance pointed to by myPointerToClass, e.g.

MyClass* myPointerToClass = new MyClass();
myPointerToClass.aMethodOfThatClass();

where

myPointerToClass->aMethodOfThatClass();

would obviously be correct.

Misogynist answered 5/3, 2013 at 9:30 Comment(0)
P
16

Parenthesis is not required to instantiate a class object when you don't intend to use a parameterised constructor.

Just use Foo foo2;

It will work.

Parody answered 1/8, 2017 at 6:43 Comment(0)
P
10

Adding to the knowledge base, I got the same error for

if(class_iter->num == *int_iter)

Even though the IDE gave me the correct members for class_iter. Obviously, the problem is that "anything"::iterator doesn't have a member called num so I need to dereference it. Which doesn't work like this:

if(*class_iter->num == *int_iter)

...apparently. I eventually solved it with this:

if((*class_iter)->num == *int_iter)

I hope this helps someone who runs across this question the way I did.

Pyrrha answered 11/2, 2014 at 21:56 Comment(0)
I
7

I was having a similar error, it seems that the compiler misunderstand the call to the constructor without arguments. I made it work by removing the parenthesis from the variable declaration, in your code something like this:

class Foo
{
  public:
    Foo() {};
    Foo(int a) {};
    void bar() {};
};

int main()
{
  // this works...
  Foo foo1(1);
  foo1.bar();

  // this does not...
  Foo foo2; // Without "()" 
  foo2.bar();

  return 0;
}
Isomagnetic answered 9/3, 2015 at 16:18 Comment(3)
This is the same answer as the one abovePterous
The most vexing parse isn't so much that the compiler misunderstood, as it is that the standard requires the compiler to interpret anything that might be a function declaration as a function declaration, to prevent ambiguity.Crisscross
(Specifically, between [stmt.ambig/1] and [dcl.ambig.res/1], the standard explicitly states that in case of ambiguity, anything that can be interpreted as a declaration IS a declaration, to resolve that ambiguity.)Crisscross
H
4

I ran into a case where I got that error message and had

Foo foo(Bar());

and was basically trying to pass in a temporary Bar object to the Foo constructor. Turns out the compiler was translating this to

Foo foo(Bar(*)());

that is, a function declaration whose name is foo that returns a Foo that takes in an argument -- a function pointer returning a Bar with 0 arguments. When passing in temporaries like this, better to use Bar{} instead of Bar() to eliminate ambiguity.

Hoofbound answered 7/9, 2017 at 11:1 Comment(0)
V
1

If you want to declare a new substance with no parameter (knowing that the object have default parameters) don't write

 type substance1();

but

 type substance;
Varico answered 8/2, 2018 at 16:49 Comment(0)
W
1

Certainly a corner case for this error, but I received it in a different situation, when attempting to overload the assignment operator=. It was a bit cryptic IMO (from g++ 8.1.1).

#include <cstdint>

enum DataType
{
  DT_INT32,
  DT_FLOAT
};

struct PrimitiveData
{
  union MyData
  {
    int32_t i;
    float f;
  } data;

  enum DataType dt;

  template<typename T>
  void operator=(T data)
  {
    switch(dt)
    {
      case DT_INT32:
      {
        data.i = data;
        break;
      }
      case DT_FLOAT:
      {
        data.f = data;
        break;
      }
      default:
      {
        break;
      }
    }
  }
};

int main()
{
  struct PrimitiveData pd;
  pd.dt = DT_FLOAT;
  pd = 3.4f;

  return 0;
}

I received 2 "identical" errors

error: request for member ‘i’ [and 'f'] in ‘data’, which is of non-class type ‘float’

(The equivalent error for clang is: error: member reference base type 'float' is not a structure or union)

for the lines data.i = data; and data.f = data;. Turns out the compiler was confusing local variable name 'data' and my member variable data. When I changed this to void operator=(T newData) and data.i = newData;, data.f = newData;, the error went away.

Whaler answered 11/8, 2018 at 21:58 Comment(0)
S
0

@MykolaGolubyev has already given wonderful explanation. I was looking for a solution to do somthing like this MyClass obj ( MyAnotherClass() ) but the compiler was interpreting it as a function declaration.

C++11 has braced-init-list. Using this we can do something like this

Temp t{String()};

However, this:

Temp t(String());

throws compilation error as it considers t as of type Temp(String (*)()).

#include <iostream>

class String {
public:
    String(const char* str): ptr(str)
    {
        std::cout << "Constructor: " << str << std::endl;
    }
    String(void): ptr(nullptr)
    {
        std::cout << "Constructor" << std::endl;
    }
    virtual ~String(void)
    {
        std::cout << "Destructor" << std::endl;
    }

private:
    const char *ptr;
};

class Temp {
public:
    Temp(String in): str(in)
    {
        std::cout << "Temp Constructor" << std::endl;
    }

    Temp(): str(String("hello"))
    {
        std::cout << "Temp Constructor: 2" << std::endl;
    }
    virtual ~Temp(void)
    {
        std::cout << "Temp Destructor" << std::endl;
    }

    virtual String get_str()
    {
        return str;
    }

private:
    String str;
};

int main(void)
{
    Temp t{String()}; // Compiles Success!
    // Temp t(String()); // Doesn't compile. Considers "t" as of type: Temp(String (*)())
    t.get_str(); // dummy statement just to check if we are able to access the member
    return 0;
}
Szombathely answered 5/5, 2020 at 18:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.