Computing the Ackermann Function
bool inputCheck(){
    if(!std::cin.fail())
        return false;

    std::cout &lt;&lt; "Invalid input!" &lt;&lt; std::endl;
    return true;
}


Carefully name your functions with a meaningful name.  inputCheck doesn't really tell anyone what to expect as a result.

Prefer to distinguish language constructs with spaces.

You can use the contextual boolean conversion operator to check the if the stream has failed rather than explicitly calling !std::cin.fail().

Prefer to avoid std::endl.  Be aware of what the manipulator std::endl actually does.  Stream '\n' as it explicitly states your intent, correctly outputs the end-of-line character, and is shorter to type.

bool isInvalidInput() {
    if (std::cin) {
        return false;
    }
    std::cout &lt;&lt; "Invalid input!\n";
    return true;
}




bool numCheck(int i, char name){
    if(i &lt; 0){ /* ... */ }
    if(name == 'm' &amp;&amp; i &gt; 3){ /* ... */ }
    if(name == 'n' &amp;&amp; i &gt; 12){ /* ... */ }
    return false;
}


Specify const for immutable variables.  const self-documents that a variable should not change values in the current scope and any accidental modification to the value is detected at compile time rather than run time.

Prefer enumerations to represent sets of related named constants.

Avoid magic constants as they are difficult to understand and may be overlooked.  Prefer symbolic constants to give values contextual meaning.



bool check(int x, char y){
    bool result = inputCheck() || numCheck(x, y);
    std::cin.clear();
    std::cin.ignore();
    return result;
}


Do you really want to ignore the remaining buffer on success?



unsigned int ackermann(unsigned int m, unsigned int n){
    if(m == 0)
        return n+1;
    if(n == 0)
        return ackermann(m-1,1);
    return ackermann(m-1,ackermann(m,n-1));
}


The Ackermann–Péter function should be tail-call optimized by any decent compiler, so you won't find much improvement with the recursive approach.  If you really care for performance, calculate Ackerman values in constant time using the formula's for \$A(m,n)\$.

$$
A(0,n) = n + 1\\
A(1,n) = n + 2\\
A(2,n) = 2n + 3\\
A(3,n) = 2^{(n+3)} - 3\\
A(4,0) = 13\\
A(4,1) = A(5,0) = 65533
$$



Contractually enforce your preconditions by testing them in the function that requires them.

namespace impl {
    unsigned Ackermann(unsigned m, unsigned n) {
        // calculate A(m,n)
    }
    void check_overflow_bounds(unsigned m, unsigned n) {
        if (m &gt; 3 || n &gt; 12) {
            throw std::out_of_bounds("");
        }
    }
}
unsigned Ackermann(unsigned m, unsigned n) {
    impl::check_overflow_bounds(m, n);
    return impl::Ackermann(m, n);
}


If your return type is an unsigned int, will Ackermann values overflow if \$m &lt; 4\$ and \$n = 13\$?  Are there Ackermann values that don't overflow when \$m = 4\$ or \$m = 5\$?  Consider what actually is computable and throw an overflow exception for values that are not computable.