-1

In c++11, constructor can be forwarded to another constructor in the initialization list.

It is fine to call function in initialization list as in this question

Is it also fine to call function in the constructor delegate?

I tried code like this:

#include <iostream>
#include <string>
#include <yaml-cpp/yaml.h>

using namespace std;

YAML::Node ParseFromFile(const string& filepath) {
  YAML::Node yaml;
  try {
    return YAML::LoadFile(filepath);
  } catch(const YAML::BadFile& e) {
    cout << "error";
  }
}

class A {
 public:
  A(YAML::Node yaml) {
    cout  << "Got" << endl;
  }
  A(const string& filepath) : A(ParseFromFile(filepath)) {}
};


int main(int argc, char** argv) {
  A a(string(argv[1]));
  YAML::Node yaml = ParseFromFile(string(argv[1]));
  A b(yaml);
  return 0;
}

For the above code, just pass an empty file to it, it will only print one "Got" during the initialization of b.

=======================================================================

Replacing string(argv[1]) with argv[1] makes it work, any ideas why?

Community
  • 1
  • 1
Min Lin
  • 3,177
  • 2
  • 19
  • 32
  • 1
    What do you mean? How is `do_something` not executed? – Brian Bi Aug 07 '14 at 05:17
  • 1
    Unrelated to your problem, but if you are using C++11 features chances are pretty good that you have [`std::to_string`](http://en.cppreference.com/w/cpp/string/basic_string/to_string) and don't have to make your own. – Some programmer dude Aug 07 '14 at 05:19
  • @Brian edited the question, the above is just an example, the exact case is not an int to string conversion. – Min Lin Aug 07 '14 at 05:21
  • @MinLin The `cout` statement *should* run. It does for me. – Brian Bi Aug 07 '14 at 05:23
  • 2
    @MinLin Maybe you should post your actual code then. Maybe your code isn't calling the constructor you think it is, and that's why you're not getting the behaviour you expect. – Brian Bi Aug 07 '14 at 05:24
  • 1
    If you just construct a temporary object, and the delegated constructor doesn't have any side-effects, it could be that the compiler optimizes out the construction. – Some programmer dude Aug 07 '14 at 05:27
  • @Brian I've posted my actual code, I can not find the problem. – Min Lin Aug 07 '14 at 05:38
  • @JoachimPileborg shouldn't be coz there's cout. – Min Lin Aug 07 '14 at 05:40
  • How do you know `ParseFile` is not called? Add some code that unambiguously tells you if if was called or not. And flush the output stream. – juanchopanza Aug 07 '14 at 05:48
  • And make sure `ParseFromFile` returns something from every path. – molbdnilo Aug 07 '14 at 05:51
  • @juanchopanza This is easy to know, just pass a nonexisting file to the code, it should print error twice. But it printed only once. – Min Lin Aug 07 '14 at 05:51
  • @molbdnilo yes in my real code it will assert and fail, at least in this code error should be printed. Please comment on the question itself. – Min Lin Aug 07 '14 at 05:53
  • That depends on many things happening. If you want to be sure of X, you shouldn't test that X, Y and Z at the same time. – juanchopanza Aug 07 '14 at 05:56
  • @MinLin Reading your new code, it seems that you had a different problem, I've updated the answer... – Scis Aug 07 '14 at 22:52

1 Answers1

3

Answer to the edited question


The problem is the first line in the main it's treated as a function declaration and not as a variable initialization, in fact have you compiled it with clang it would've give you a warning about this:

warning: parentheses were disambiguated as a function declaration

This is due what is defined in § 6.8 Ambiguity resolution in the standard (AKA Most vexing parse) (emphasis mine... ):

There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.

Consider the following example:

#include <iostream>
#include <string>
#include <exception>
using namespace std;

struct A{
    string a;
    A(string s) : a(s){ cout<< "Ctor" <<endl;}
    A(int i) : A(to_string(i)){ }
};

void foo (A (*a)(string*)){
    cout<<"yay"<<endl;
}

int main(int argc, char** argv) {
    A         a1(     string(argv[1]) ); // function A a1(std::string*) declaration not a variable 
/*  ^         ^       ^
    |         |       |
return type   name   arg type 
Same as foo
*/
    // foo(a1);//  <- compiles but fails only due to linkage         
    A  a2 = A(string(argv[1])); // works
    A  a3{string(argv[1])}; // works
    A  a4(string{argv[1]}); // works
    A         a5(     ( string(argv[1]) ) ); // works allso but confusing imho
/*                    ^                 ^
notice extra paren.   |                 |
*/  
    return 0;
}

Answer to the original question FWIW


Why not just try?

There should be no problem unless you call a function that will use members that are still uninitialized.

E.g (demo):

#include <iostream>
#include <string>
using namespace std;

class A {
 public:
  A(string x) {
    cout  << "Got "  << x << endl;
  }
  A(int x) : A(std::to_string(x)) {}
};


int main() {
    A a(15);
    return 0;
}
Scis
  • 2,934
  • 3
  • 23
  • 37
  • You shouldn't use any non-static members of the current class whatsoever, the object's lifetime hasn't begin. Initialization hasn't even begun yet, because the primary constructor hasn't begun. Calling a global function, as in the question, members of constructor arguments, or static members of the current class should all be just fine. – Ben Voigt Aug 07 '14 at 05:33
  • @Scis Your code executes fine, I've posted my actual problem, it is not working. – Min Lin Aug 07 '14 at 05:44
  • 1
    @BenVoigt you can use non-static members as long as you are careful about the order in which you declared them: http://stackoverflow.com/q/4162021/819272 – TemplateRex Aug 07 '14 at 07:58