Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template Class wrong copy constructor called

Tags:

c++

templates

Solution

To avoid the problem with the std::auto_ptr one can switch to boost::shard_ptr or C++11 std::shared_ptr.

I get an error that the wrong copy constructor is called in my template class:

MPINetworkCode.hpp: error: no matching function for call to 
MPILib::MPINode<double>::MPINode(MPILib::MPINode<double>)

MPINode.hpp: note: candidate is: 
MPILib::MPINode<double>::MPINode(MPILib::MPINode<double>&)

Here are the code lines which result in this error.

int MPINetwork<WeightValue>::AddNode(const AlgorithmInterface<WeightValue>& alg,
    NodeType nodeType) {

    MPINode<WeightValue> node = MPINode<WeightValue>(alg, nodeType, 
          tempNodeId, _nodeDistribution, _localNodes);
    _localNodes.insert(std::make_pair(tempNodeId, node));
}

What is wrong with this code, and why is the wrong copy constructor is called? In a previous version of this class without templates this worked fine.

Here the header of the related classes. The template implementation are in a header file.

Here the MPINetwork:

template <class WeightValue>
class MPINetwork: private boost::noncopyable {

public:

    explicit MPINetwork();

    ~MPINetwork();

    /**
     * Adds a new node to the network
     * @param alg The Algorithm of the actual node
     * @param nodeType The Type of the Node
     * @return returns the NodeId of the generated node
     */
    int AddNode(const AlgorithmInterface<WeightValue>& alg, NodeType nodeType);

//lot of code

};

And the second MPINode, where the default copy constructor should be called:

template <class Weight>
class MPINode {
public:
    /**
     * Constructor
     * @param algorithm Algorithm the algorithm the node should contain
     * @param nodeType NodeType the type of the node
     * @param nodeId NodeId the id of the node
     * @param nodeDistribution The Node Distribution.
     * @param localNode The local nodes of this processor
     */
    explicit MPINode(const AlgorithmInterface<Weight>& algorithm, NodeType nodeType,
            NodeId nodeId,
            const boost::shared_ptr<utilities::NodeDistributionInterface>& nodeDistribution,
            const std::map<NodeId, MPINode<Weight> >& localNode);

    virtual ~MPINode();

    Time Evolve(Time time);

    void ConfigureSimulationRun(const SimulationRunParameter& simParam);

    void addPrecursor(NodeId nodeId, const Weight& weight);

    void addSuccessor(NodeId nodeId);

    NodeState getState() const;

    void setState(NodeState state);

    void receiveData();

    void sendOwnState();

private:

    void waitAll();

    std::vector<NodeId> _precursors;

    std::vector<Weight> _weights;

    std::vector<NodeId> _successors;

    std::auto_ptr<AlgorithmInterface<Weight> > _algorithm;

    NodeType _nodeType;

    NodeId _nodeId;

    const std::map<NodeId, MPINode>& _refLocalNodes;

    boost::shared_ptr<utilities::NodeDistributionInterface> _nodeDistribution;

    NodeState _state;

    std::vector<NodeState> _precursorStates;

    std::vector<boost::mpi::request> _mpiStatus;
};

template<class Weight>
MPINode<Weight>::MPINode(const AlgorithmInterface<Weight>& algorithm, NodeType nodeType,
        NodeId nodeId,
        const boost::shared_ptr<utilities::NodeDistributionInterface>& nodeDistribution,
        const std::map<NodeId, MPINode>& localNode) :
        _algorithm(algorithm.Clone()), _nodeType(nodeType), _nodeId(nodeId), _nodeDistribution(
                nodeDistribution), _refLocalNodes(localNode) {

}
like image 203
tune2fs Avatar asked Aug 19 '26 19:08

tune2fs


2 Answers

Your problem is essentially caused by this member:

std::auto_ptr<AlgorithmInterface<Weight> > _algorithm;

std::auto_ptr's copy constructor doesn't really copy, it transfers ownership. Because of this it takes a non-const reference to its argument, not a const reference.

This means that when the compiler comes to generate the copy constructor for an MPINode specialization it cannot generate a copy constructor that takes a const reference to another MPINode, it can only generate one that takes a non const reference.

In this initialization, the temporary MPINode<WeightValue> cannot bind to the non-const reference parameter that the generated copy constructor requires.

MPINode<WeightValue> node = MPINode<WeightValue>(alg, nodeType, 
      tempNodeId, _nodeDistribution, _localNodes);

How to fix this depends on your design. It might be that supplying a user-defined copy constructor that takes const reference and properly clones the _algorithm member is the correct approach.

like image 125
CB Bailey Avatar answered Aug 22 '26 10:08

CB Bailey


Your compiler seems to be generating a copy constructor for you that accepts an argument of type MPILib::MPINode<double>&. Try defining your own copy constructor that takes the type const MPILib::MPINode<double>&. The initialization of the variable node in AddNode is invoking the copy constructor, and the compiler does not let you pass a temporary into a function that expects a modifiable reference.

like image 44
jxh Avatar answered Aug 22 '26 09:08

jxh



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!