Reputation: 2260
class Edge:
class Edge {
int dist = 0;
std::pair<Node, Node> ends;
public:
Edge() = default;
explicit Edge(const int idist) : dist(idist) { }
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist) {
ends.first = end1;
ends.second = end2;
}
~Edge() = default;
};
In the ctor explicit Edge(const int idist, Node& end1, Node& end2)
, why am I not allowed to use the syntax?:
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist), ends.first(end1), ends.second(end2) { }
Upvotes: 1
Views: 66
Reputation: 76523
One of the fundamental features of C++ classes is that every object (absent malice) will be properly created by its constructor. Looked at the other way around, if a type has a constructor, then you must create objects of that type with the constructor.
In the constructor initializer list for Edge
, each member of Edge
gets constructed. Since std::pair
has its own constructor, constructing an Edge
object means constructing that ends
member with the appropriate constructor for std::pair
.
That's not something you should be trying to bypass. It's fundamental to sound programming. Constructors create objects. Doing your own thing risks creating things that haven't been properly created. Yes, in this particular case, you can probably get away with it. But there's nothing to gain from bypassing the constructor, and in other cases, that would cause significant problems. Don't bypass constructors. Let them do their job, so your job will be much easier.
Upvotes: 0
Reputation: 173044
This is just not allowed. As the syntax of member initializer list,
class-or-identifier ( expression-list(optional) ) (1) class-or-identifier brace-init-list (2) (since C++11)
While ends.first
and ends.second
don't refer to class or identifier, they're expressions. You have to initialize ends
in whole, e.g.
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist), ends(end1, end2) { }
Upvotes: 4
Reputation: 944
What you're trying to do is allowed, but the way you're doing it isnt.
The initializer list specifies how to turn a random bit of memory containing uninitialized bytes into a valid object. The constructor can then do things with this new object, but the object state needs to be initialized beforehand. There are some caveats to this surrounding uninitialized values resulting from default initialization, but the only valid thing to do in an initializer list is call a member's constructor. (See here for more on default initialization.)
In your case, first
and second
are fields of a pair
. You can't access them until the pair has been constructed. And even then, you couldn't necessarily re-initialize them the way you're attempting to.
The solution is to initialize the whole pair at once using one of its constructors:
explicit Edge(const int idist, Node& end1, Node& end2) : dist(idist), ends(end1, end2) { }
Upvotes: 1