1

I'm working on a C++ file that can perform Huffman encoding and ran into a bit of an issue when changing from a map of type string and int to a queue of type Node and was wondering if there is a way to define an explicit conversion from a pair of strings and ints to a Node.

Currently, I have it so that the map is converted to a vector of pairs then converted into a vector of type Node then into a priority queue of type Node.

// this->char_freqs is of type map<std::string, int>
std::vector<std::pair<std::string, int> > my_vector(this->char_freqs.begin(), this->char_freqs.end());
  std::vector<Huffman::Node*> real_vector;
  for (unsigned int i = 0; i < my_vector.size(); ++i) {
    real_vector.push_back(new Huffman::Node(my_vector[i].first, my_vector[i].second));
  }
  std::priority_queue<Huffman::Node*, std::vector<Huffman::Node*>, Huffman::comp> PQ(real_vector.begin(), real_vector.end());

I haven't tested if this would work yet. However I am more so looking to develop a method that could explicitly define a conversion from pair<string, int> to Node* so that the transition from a map to queue could be done in essentially one line. Something like:

std::priority_queue<Huffman::Node*, std::vector<Huffman::Node*>, Huffman::comp> PQ(this->char_freqs.begin(), this->char_freqs.end());

In reading the documentation I have only found examples of converting user defined types to default types and not the other way around.

Edit 1

This should hopefully be simpler and explain what I'm looking for.

class Node {
 public:
  char character;
  int frequency;
  Node(char char_, int val_) {
    character = char_;
    frequency = val_;
  }
  operator std::pair<char, int>() {
    return std::pair<char, int>(character, frequency);
  }
};
int main(int argc, char** argv) {
  std::vector<std::pair<char, int> > my_vector_1;
  Node n('a', 3);
  my_vector_1.push_back(n); // Can use a Node as an input since the conversion has been explicitly defined

  std::vector<Node> my_vector_2;
  std::pair<char, int> pair('a', 3);
  my_vector_2.push_back(pair); // Invalid
}

Of course, the invalid option would fail because the compiler has no way of converting a pair into a Node, but is it possible to make the invalid line work?

2 Answers2

3

If I understand your issue correctly, what you need is another constructor for Node, something like this

Node(const std::pair<char, int>& pair) : character{pair.first}, 
                                         frequency{pair.second} { }

Note that I am using the member initializer list to initialize the data of your class. This is the recommended way to do so, see for more info https://en.cppreference.com/w/cpp/language/initializer_list

Going forward you might want to mark the constructor as explicit to avoid unwanted conversions (see What does the explicit keyword mean?) and use emplace_backinstead of push_back to avoid the construction of a temporary https://en.cppreference.com/w/cpp/container/vector/emplace_back. The marking of the constructor to explicit might not fit your use case, the choice is yours. If you mark the constructor explicit the push_back as written now will stop working, you will need to create explicitly a Node or use emplace_back.

1

The problem comes under Implicit conversion.
Implicit conversion is defined in terms of copy-initialization: if an object of type T can be copy-initialized with expression E, then E is implicitly convertible to T.
Now consider following example,

#include <iostream>
#include <utility>

class Point
{
public:
    Point():x(),y()
    {
    }

    Point( const std::pair< int, int>& pair):
        x( pair.first),
        y( pair.second)
    {

    }

    int getX() const
    {
        return x;
    }

    int getY() const
    {
        return y;
    }

private:
    int x;
    int y;
};

int main(int , char *[])
{
    Point p = std::pair< int, int>( 1, 2);
    std::cout<< "x = "<< p.getX()<< ", y = "<< p.getY()<< std::endl;

    return 0;
}

output x = 1, y = 2

Here std::pair< int, int> is implicitly convertible to Point type.
Another point is, if you use explicit with Point( const std::pair< int, int>& pair) then you can't use above syntax in that case you have to modify it to Point p( std::pair< int, int>( 1, 2));
For more information please see following link copy_initialization .

Vikas Awadhiya
  • 290
  • 1
  • 8