Conflicting declaration when passing file stream to constructor

58 views Asked by At

I'm trying to make 2 constructors to a class, where one opens the file, checks for errors, and calls the other one. But I can't get it to work. I get the error:

Conflicting declaration 'A file'

Can I not call a constructor inside another one? I always thought I could.

Code:

#include <iostream>
#include <fstream>

class A {
  int a = 0;
public:
  A()=default;
  explicit A(char *filename);
  explicit A(std::ifstream &file);
};

A::A(char *filename) {
  std::ifstream file(filename);

  if(!file.is_open()) {
    std::cout << "ERROR!\n";
    A();
    return;
  }

  A(file); // Compilation error here

  file.close();
}

int main()
{
    return 0;
}
1

There are 1 answers

0
Remy Lebeau On BEST ANSWER

Can I not call a constructor inside another one? I always thought I could.

You can, but not the way you are trying to.

In your example, the compiler is treating this statement:

A(file);

The same as if you had written this instead:

A file;

(see Which part of the C++ standard allow to declare variable in parenthesis?)

But, you already have an existing variable named file, hence the conflict.

Delegating constructors only work in the member initialization list, eg:

#include <iostream>
#include <fstream>

class A {
  int a = 0;
public:
  A() = default;
  explicit A(char *filename);
  explicit A(std::ifstream &file);
};

A::A(char *filename) :
  A(std::ifstream(filename)) {
}

A::A(std::ifstream &file) : A() {
  if (!file.is_open()) {
    std::cout << "ERROR!\n";
  }
}

int main()
{
    A a("file.txt");
    return 0;
}

However, that won't work in your example since you can't take a non-const reference to a temporary object. So, you will have to break out the stream operations into a separate method that both constructors can call, eg:

#include <iostream>
#include <fstream>

class A {
  int a = 0;
  void doSomething(std::ifstream &file);
public:
  A() = default;
  explicit A(char *filename);
  explicit A(std::ifstream &file);
};

A::A(char *filename) : A() {
  std::ifstream file(filename);

  if (!file.is_open()) {
    std::cout << "ERROR!\n";
    return;
  }

  doSomething(file);
}

A::A(std::ifstream &file) : A() {
  doSomething(file);
}

A::doSomething(std::ifstream &file) {
  ... 
}

int main()
{
    A a("file.txt");
    return 0;
}