I wrote a function template to compute the GCD of two integers. This function checks that its arguments are an integral type. I also wrote a function template which accepts a pair of iterators in order to compute the GCD of two or more integers. It calls the first function to compute the GCD of pairs of integers.

Here is the code for the GCD functions, as well as some code in `main()` to demonstrate and test the use of the functions:

```
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <list>
#include <iterator>
#include <stdexcept>

/** \brief Computes the greatest common divisor of its arguments.
\tparam integer a type for which
[std::is_integral](http://en.cppreference.com/w/cpp/types/is_integral)
returns `true`
*/
template <typename integer,
    typename = std::enable_if_t<std::is_integral<integer>::value> >
integer gcd(integer a, integer b) {
    // Make sure arguments are positive since gcd is always positive
    if (a < 0) a = -a;
    if (b < 0) b = -b;

    if (a == 0) return b; // gcd(0, b) = |b|

    // Euclid's algorithm
    while (b != 0) {
        if (a > b) a -= b;
        else b -= a;
    }
    return a;
}

/** \brief Computes the greatest common divisor of the integers in the range
[first, last).
\tparam Iter must meet the requirements of
[InputIterator](http://en.cppreference.com/w/cpp/concept/InputIterator)
\tparam integer a type for which
[std::is_integral](http://en.cppreference.com/w/cpp/types/is_integral)
returns `true`
\param[in] first the iterator pointing to the first element
\param[in] last the iterator pointing to one past the last element
\return the greatest common divisor of the integers in the range [first, last)
*/
template <typename Iter, typename integer = typename Iter::value_type>
integer gcd(Iter first, Iter last) {
    auto n = std::distance(first, last);

    if (n < 2) throw std::invalid_argument("must have at least two values");

    // Compute the gcd of the first two integers
    auto d = gcd(*first, *std::next(first));

    // Iterate through remaining integers using the fact that gcd(a, b, c) = gcd(gcd(a, b), c)
    auto iter = std::next(first, 2); // iterator to the third integer

    while (iter != last) {
        d = gcd(d, *iter);
        ++iter;
    }

    return d;
}

int main() {
  std::cout << "Testing the basic gcd():\n";
  std::cout << gcd(4, 8) << "\n";
  std::cout << gcd(54, 24) << "\n";
  std::cout << gcd(-42, 56) << "\n";
  std::cout << gcd(18, -84) << "\n";
  std::cout << gcd(4, 0) << "\n";
  std::cout << gcd(0, 8) << "\n";
  std::cout << gcd(0, 0) << "\n";

  // would correctly result in compile error
  //std::cout << gcd(4.9, 8) << "\n";

  std::cout << "\nTesting the range-based gcd():\n";

  std::vector<int> v;
  std::set<int> s;
  std::list<int> li;

  // Test gcd() with the vector

  try {
      std::cout << gcd(v.begin(), v.end()) << "\n";
  } catch (const std::invalid_argument& e) {
      std::cout << "Correctly caught exception (empty vector): " << e.what() << "\n";
  }

  // Add one element to v
  v.push_back(4);

  try {
      std::cout << gcd(v.begin(), v.end()) << "\n";
  } catch (const std::invalid_argument& e) {
      std::cout << "Correctly caught exception (only one element in vector): " << e.what() << "\n";
  }

  // Add second element to v
  v.push_back(8);
  std::cout << gcd(v.begin(), v.end()) << "\n";

  // Add third element to v
  v.push_back(8);
  std::cout << gcd(v.begin(), v.end()) << "\n";

  // Add fourth element to v
  v.push_back(14);
  std::cout << gcd(v.begin(), v.end()) << "\n";

  try {
      std::cout << gcd(v.begin(), v.begin()) << "\n";
  } catch (const std::invalid_argument& e) {
      std::cout << "Correctly caught exception (v.begin() used for both arguments): " << e.what() << "\n";
  }

  // Test gcd() with the set

  s.insert(8);
  s.insert(4);
  s.insert(14);
  s.insert(-8);
  std::cout << "Using std::set: " << gcd(s.begin(), s.end()) << "\n";

  // Test gcd() with the list

  li.push_back(8);
  li.push_back(4);
  li.push_back(14);
  li.push_back(-8);
  std::cout << "Using std::list: " << gcd(li.begin(), li.end()) << "\n";
}

```

I'm looking for suggestions to improve any aspect of the code. Some specific questions:

1. Should the iterator-based `gcd()` have a different name like `multigcd()` or is it clear enough to use `gcd()` for both? Is it confusing that `gcd()` takes two arguments regardless of how many integers are actually part of the calculation? Any other naming advice?
2. Are the comments sufficient?
3. Is `std::invalid_argument` the correct exception to throw? Is the explanatory string for it sufficiently descriptive?