C ++ declares a function instead of calling a complex constructor

Firstly, I know that there are similar questions already about stackoverflow ( this , this and this ), and that is why I understand the cause of my problem. Unfortunately, this does not help me solve this problem.

While the above questions are about the default no-parameter constructor, I have a problem when using two parameter constructors with default values ​​- I tried to build an object that calls the constructor with only the first value given, and this is parsed as declaring a function instead of an object .

Here are some snippets of my code (I renamed the class names because they are long and not relevant):

class algoContainer{ public: algoContainer(algo1Virtual &alg1 = algo1Concrete::emptyInstance(), algo2Virtual &alg2 = algo2Concrete::instance()); someUsefulFunction(); }; class algo1Concrete : public algo1Virtual{ private: algo1Concrete(); public: static algo1Concrete &emptyInstance(); // "empty" instance treated // specifically // -- uses private no arg constructor algo1Concrete(const std::vector<data> &myData); // construcotr }; class algo1Virtual{ // ... all functions virtual, no implementations ... }; // ... similar for algo2Virtual/Concrete ... 

All functions in the Concrete classes are implemented, while none of them in the Virtual classes (except for constructors and destructors).

So now my problem is that I want to do something like :

 std::vector <data> workData; // fill workData algoContainer myAC(algo1Concrete(workData)); myAC.someUsefulFunction(); // this line gives compile error 

Nice, cute and ellegant, but it doesn’t work (the error is the same as all the issues that I have connected ). I found this tutorial forum that refers to the problem as the most unpleasant parsing, but this solution (putting parentheses around the argument) t solve the problem (this is a long group of error messages in this case, but I can edit it in the question later if this helps - all this is related to the inheritance of a virtual function).

I tested my code if I use a constructor with all the default parameters, and even if I just build the first parameter separately:

 std::vector <data> workData; // fill workData algo1Concrete myA1(workData); algoContainer myAC(myA1); myAC.someUsefulFunction(); // now it works fine algoContainer myAC2; myAC2.someUsefulFunction(); // this also works 

I can use the code as is, but it would be very appreciated if someone could give me a more elegant solution for the one that I'm using right now.


EDIT : The error messages I get when I fix the most unpleasant parsing

If I use the code with parenthesis:

 algoContainer myAC((algo1Concrete(workData))); 

My mistakes:

 /some_path/main.cpp:47:65: error: no matching function for call to 'algoContainer::algoContainer(algo1Concrete)' /some_path/main.cpp:47:65: note: candidates are: /some_path/algo/algocont.h:45:5: note: algoContainer::algoContainer(algo1Virtual&, algo2Virtual&) /some_path/algo/algocont.h:45:5: note: no known conversion for argument 1 from 'algo1Concrete' to 'algo1Virtual&' /some_path/algo/algocont.h:36:7: note: algoContainer::algoContainer(const algoContainer&) /some_path/algo/algocont.h:36:7: note: no known conversion for argument 1 from 'algo1Concrete' to 'const algoContainer&' 

I renamed the paths and inserted sample files and class names (same as above) for readability. Just a note: line 45 is the definition of the constructor in question. line 36 , on the other hand, is a class algoContainer line.

I also tried with this code:

 algoContainer myDect((algo1Virtual)(algo1Concrete(workData))); 

And then the errors are completely different:

 /some_path/main.cpp:47:86: error: cannot allocate an object of abstract type 'algo1Virtual' /some_path/algo/alg1/algo1virtual.h:31:7: note: because the following virtual functions are pure within 'algo1Virtual': /some_path/algo/alg1/algo1virtual.h:42:8: note: virtual algo1Virtual::~algo1Virtual() /some_path/algo/alg1/algo1virtual.h:39:18: note: virtual void algo1Virtual::someAlgo1Function(std::vector<data>&) /some_path/main.cpp:47:87: error: no matching function for call to 'algoContainer::algoContainer(algo1Virtual)' /some_path/main.cpp:47:87: note: candidates are: /some_path/algo/algocont.h:45:5: note: algoContainer::algoContiner(algo1Virtual&, algo2Virtual&) /some_path/algo/algocont.h:45:5: note: no known conversion for argument 1 from 'algo1Virtual' to 'algo1Virtual&' /some_path/algo/algocont.h:36:7: note: algo1Virtual::algo1Virtual(const algo1Virtual&) /some_path/algo/algocont.h:36:7: note: no known conversion for argument 1 from 'algo1Virtual' to 'const algo1Virtual&' 

Hope this helps.

+6
source share
4 answers

The problem seems to be related to the arguments that the constructor executes:

 algoContainer( algo1Virtual &alg1, algo2Virtual &alg2 ); 

Note. I shortened the default arguments for brevity.

this takes arguments as non-constant references. Therefore, when you make a call, for example:

 algoContainer myAC(algo1Concrete(workData)); 

building:

 algo1Concrete(workData) 

leads to the creation of an anonymous temporary. Anonymous temporary users cannot link to non-constant links, simply because they are temporary, and any changes you could make to them will disappear instantly (this is not a real reason, but it seems to make sense. It does not mean anything to change anonymous temporarily, because you have no way to use it later (no name) or ultimately (its temporary)). In fact, links that do not contain constants can only bind to l values, and anonymous temporary values ​​to r values. (More: Link cannot be attached only to lvalue )

In general, this type of use means that a person wants to completely own the object created for this function. This can be done either by passing by value (expensive) or in C ++ 11 by passing by rvalue reference.

Passing by value will look like this:

 algoContainer( algo1Virtual alg1, algo2Virtual alg2 ); 

This will result in unnecessary copies.

Another option is to pass the rvalue reference in C ++ 11, for example:

 algoContainer( algo1Virtual &&alg1, algo2Virtual &&alg2 ); 

Now your first use will work out of the box:

 std::vector <data> workData; // fill workData algoContainer myAC(algo1Concrete(workData)); myAC.someUsefulFunction(); 

but you will need to change the second use so that your object is "moved" to the constructor, and algoContainer takes responsibility for the data (the local name variable is "bad") and should NOT be used at all.

 std::vector <data> workData; // fill workData algo1Concrete myA1(workData); algoContainer myAC(std::move(myA1)); //NOTICE THE std::move call. //myA1 is now a dummy, and unusable as all the internals have gone. myAC.someUsefulFunction(); 

For this above example to work, you will need to implement a move constructor for algo1Concrete with the following signature:

 algo1Concrete ( algo1Concrete&& other ) 

which simply transfers the insides to the current state and leaves the β€œother” in undefined state. (More: http://msdn.microsoft.com/en-us/library/dd293665.aspx )

NOTE. Regarding the default arguments.

I usually suggest avoiding the default arguments for functions, as they lead to more confusion than convenience. All default parameters can be "simulated" by simply overloading the function. So in your case you will have three ctors:

 algoContainer(); //This assumes that the args were both the statics algoContainer( algo1Virtual alg1 ); //This assumes that arg2 was the static. algoContainer( algo1Virtual alg1, algo2Virtual alg2 ); //This uses both input. 

I agree with it being more detailed, and not many compilers currently implement constructor inheritance, so we also copy code quite often. But this isolates one of several debugging / magic value issues that come up when investigating a problem. But, FWIW, this is just an opinion.

+3
source

algoContainer myAC (algo1Concrete (workData));

This line is illegal. You cannot bind rvalue to mutable lvalue reference. It must be const - and even if that were the case, the object would die before it could be used by any function except the constructor.

+3
source

Write this:

 algoContainer myAC((algo1Concrete(workData))); 

Then search the Internet for "the most annoying parsing." There are hundreds of duplicates of this question in StackOverflow, but they are hard to find because the problem is never identified in the question itself. (If it were, there would be no doubt.)


(After editing) Temporary objects (for example, functions created by calling functions that return by value) are not bound to mutable references. You must say:

 algo1Concrete ac = algo1Concrete(workData); algoContainer myAC(ac); 
0
source

As an alternative to the current solution, you can use an extra pair of parentheses or use copy initialization.

0
source

Source: https://habr.com/ru/post/911105/


All Articles