Is this good c++ code for a pin/socket for a node editor? I'm trying to create a node editor "framework" (IDK what to call it, but essentially there is no GUI and should be implemented using these classes), similar to rete.js, blueprints(maybe an exception since there are events involved), imnodes, etc; and am creating a pin class/struct.

A pin, in this case, is the small things you actually connect (those circles on the sides of the actual nodes which can be inputs or outputs).

I'm using a single header, since almost everything I look into recommends using it for templated classes.

I think there are many problems in the code in general, but another thing that has been bugging me is the naming of classes, enums, members, etc., especially the naming of PinType, InputOutputCount (including the members itself), IOCount.

#pragma once

#include &lt;string&gt;
#include &lt;vector&gt;

enum PinType {//Whether or not the pin takes in values from other pins(input) or gives the value to other pins(output). TODO: Name change.
    INPUT,
    OUTPUT
};

enum InputOutputCount {//How many stuff the pin can take in or give out. TODO: Name change.
    NOTHING = 0,//Is this redundant?
    ONE = 1,
    MULTIPLE = -1
};

struct PinAbstract {//An abstract superclass for the actual Pin class, in order to store it in vectors, since Pin is a templated class.
    PinType Type;
    InputOutputCount IOCount = ONE;
    virtual ~PinAbstract() = 0;//Don't know much about destructors, but this was the only thing that worked for me.
};

template &lt;class T&gt;
struct Pin : public PinAbstract {//The actual pin class
    std::string Title = "Title";//The title of the pin
    T* Value = nullptr;//The value passed or being given.
    std::vector&lt;Pin&lt;T&gt;*&gt; Connections = {};//The other pins this pin is connected to. NOTE: same template type since two connected pins should be of same type. So a string input only takes in from a string output.
};

template &lt;class T&gt;
void ConnectPins(Pin&lt;T&gt; *pin1, Pin&lt;T&gt; *pin2) {//NOTE: same template type for the same reason above.
    if (((pin1-&gt;Type == OUTPUT &amp;&amp; pin2-&gt;Type == INPUT) || (pin1-&gt;Type == INPUT &amp;&amp; pin2-&gt;Type == OUTPUT)) &amp;&amp; ((int)pin1-&gt;IOCount - pin1-&gt;Connections.size() != 0 &amp;&amp; (int)pin2-&gt;IOCount - pin2-&gt;Connections.size() != 0)) {
/*Only connect input with output and vice-versa AND make sure that connection doesn't exceed max connections of any one of the pins*/
        pin1-&gt;Connections.push_back(pin2);
        pin2-&gt;Connections.push_back(pin1);
    }
}


Any sort of help is greatly appreciated. Including things that are not even code, including naming fixes, general strategies, etc.
Input and output count
enum InputOutputCount {
    NOTHING = 0, //Is this redundant?
    ONE = 1,
    MULTIPLE = -1
};

Yes, I think a pin that does not allow anything to connect to it is redundant. This could be replaced with a simple bool that indicates whether multiple connections are allowed or not.
Note that it doesn't make sense to restrict the number of connections to an output pin, there is nothing ambiguous about that. However, for input pins there is ambiguity: what should you do if there are multiple, different values on the input? Do you pick one, sum them, average them, multiply them? So there it does make sense to restrict the input to just one connection.
Make Pin::Value a reference
Does it make sense for Value to be a null pointer? After setting the pointer, can the pointer change? If the answer to both of these questions is no, then it is better to make it a reference, like so:
template &lt;class T&gt;
struct Pin: PinAbstract {
    ...
    T &amp;value;
    ...
};

You should add a constructor that initializes the reference, so that it is not possible to construct a concrete Pin without a correct reference. You can also use this to ensure the title is always set to something useful, like so:
template &lt;class T&gt;
struct Pin: PinAbstract {
    const std::string Title;
    T &amp;value;
    std::vector&lt;Pin&gt; Connections;

    Pin(T &amp;value, const std::string &amp;title): Value(value), Title(title) {}
};

Return an error if a connection cannot be made
Your function ConnectPins() silently ignores errors when trying to connect two incompatible pins together. Consider adding some way of reporting an error. It can be as simple as returning a bool indicating success, or you could throw an exception. This could then be used by the UI to display an error message.
Pass pins by reference to ConnectPins()
Similar to why you might want to use a reference instead of a pointer for Pin::Value, since you should never pass a NULL pointer to ConnectPins(), it is better to pass them by reference:
template &lt;class T&gt;
bool ConnectPins(Pin&lt;T&gt; &amp;pin1, Pin&lt;T&gt; &amp;pin2) {
    if (pin1.Type != pin2.Type)
        return false;
    ...

    pin1.Connections.push_back(&amp;pin2);
    pin2.Connections.push_back(&amp;pin1);
    return true;
}