text: // This file was GENERATED by command:
  //     pump.py gtest-param-util-generated.h.pump
  // DO NOT EDIT BY HAND!!!
  
  // Copyright 2008 Google Inc.
  // All Rights Reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  //     * Redistributions of source code must retain the above copyright
  // notice, this list of conditions and the following disclaimer.
  //     * Redistributions in binary form must reproduce the above
  // copyright notice, this list of conditions and the following disclaimer
  // in the documentation and/or other materials provided with the
  // distribution.
  //     * Neither the name of Google Inc. nor the names of its
  // contributors may be used to endorse or promote products derived from
  // this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  
  // Type and function utilities for implementing parameterized tests.
  // This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
  //
  // Currently Google Test supports at most 50 arguments in Values,
  // and at most 10 arguments in Combine. Please contact
  // googletestframework@googlegroups.com if you need more.
  // Please note that the number of arguments to Combine is limited
  // by the maximum arity of the implementation of tuple which is
  // currently set at 10.
  
  // GOOGLETEST_CM0001 DO NOT DELETE
  
  #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
  #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
  
  #include <cassert>
  
  #include <memory>
  
  #include "gtest/internal/gtest-param-util.h"
  #include "gtest/internal/gtest-port.h"
  
  namespace testing {
  
  namespace internal {
  // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
  //
  // Generates values from the Cartesian product of values produced
  // by the argument generators.
  //
  template <typename T1, typename T2>
  class CartesianProductGenerator2
      : public ParamGeneratorInterface< ::std::tuple<T1, T2> > {
   public:
    typedef ::std::tuple<T1, T2> ParamType;
  
    CartesianProductGenerator2(const ParamGenerator<T1>& g1,
        const ParamGenerator<T2>& g2)
        : g1_(g1), g2_(g2) {}
    virtual ~CartesianProductGenerator2() {}
  
    virtual ParamIteratorInterface<ParamType>* Begin() const {
      return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
    }
    virtual ParamIteratorInterface<ParamType>* End() const {
      return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
    }
  
   private:
    class Iterator : public ParamIteratorInterface<ParamType> {
     public:
      Iterator(const ParamGeneratorInterface<ParamType>* base,
        const ParamGenerator<T1>& g1,
        const typename ParamGenerator<T1>::iterator& current1,
        const ParamGenerator<T2>& g2,
        const typename ParamGenerator<T2>::iterator& current2)
          : base_(base),
            begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
            begin2_(g2.begin()), end2_(g2.end()), current2_(current2)    {
        ComputeCurrentValue();
      }
      virtual ~Iterator() {}
  
      virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
        return base_;
      }
      // Advance should not be called on beyond-of-range iterators
      // so no component iterators must be beyond end of range, either.
      virtual void Advance() {
        assert(!AtEnd());
        ++current2_;
        if (current2_ == end2_) {
          current2_ = begin2_;
          ++current1_;
        }
        ComputeCurrentValue();
      }
      virtual ParamIteratorInterface<ParamType>* Clone() const {
        return new Iterator(*this);
      }
      virtual const ParamType* Current() const { return current_value_.get(); }
      virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
        // Having the same base generator guarantees that the other
        // iterator is of the same type and we can downcast.
        GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
            << "The program attempted to compare iterators "
            << "from different generators." << std::endl;
        const Iterator* typed_other =
            CheckedDowncastToActualType<const Iterator>(&other);
        // We must report iterators equal if they both point beyond their
        // respective ranges. That can happen in a variety of fashions,
        // so we have to consult AtEnd().
        return (AtEnd() && typed_other->AtEnd()) ||
           (
            current1_ == typed_other->current1_ &&
            current2_ == typed_other->current2_);
      }
  
     private:
      Iterator(const Iterator& other)
          : base_(other.base_),
          begin1_(other.begin1_),
          end1_(other.end1_),
          current1_(other.current1_),
          begin2_(other.begin2_),
          end2_(other.end2_),
          current2_(other.current2_) {
        ComputeCurrentValue();
      }
  
      void ComputeCurrentValue() {
        if (!AtEnd())
          current_value_.reset(new ParamType(*current1_, *current2_));
      }
      bool AtEnd() const {
        // We must report iterator past the end of the range when either of the
        // component iterators has reached the end of its range.
        return
            current1_ == end1_ ||
            current2_ == end2_;
      }
  
      // No implementation - assignment is unsupported.
      void operator=(const Iterator& other);
  
      const ParamGeneratorInterface<ParamType>* const base_;
      // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
      // current[i]_ is the actual traversing iterator.
      const typename ParamGenerator<T1>::iterator begin1_;
      const typename ParamGenerator<T1>::iterator end1_;
      typename ParamGenerator<T1>::iterator current1_;
      const typename ParamGenerator<T2>::iterator begin2_;
      const typename ParamGenerator<T2>::iterator end2_;
      typename ParamGenerator<T2>::iterator current2_;
      std::shared_ptr<ParamType> current_value_;
    };  // class CartesianProductGenerator2::Iterator
  
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductGenerator2& other);
  
    const ParamGenerator<T1> g1_;
    const ParamGenerator<T2> g2_;
  };  // class CartesianProductGenerator2
  
  
  template <typename T1, typename T2, typename T3>
  class CartesianProductGenerator3
      : public ParamGeneratorInterface< ::std::tuple<T1, T2, T3> > {
   public:
    typedef ::std::tuple<T1, T2, T3> ParamType;
  
    CartesianProductGenerator3(const ParamGenerator<T1>& g1,
        const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
        : g1_(g1), g2_(g2), g3_(g3) {}
    virtual ~CartesianProductGenerator3() {}
  
    virtual ParamIteratorInterface<ParamType>* Begin() const {
      return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
          g3_.begin());
    }
    virtual ParamIteratorInterface<ParamType>* End() const {
      return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
    }
  
   private:
    class Iterator : public ParamIteratorInterface<ParamType> {
     public:
      Iterator(const ParamGeneratorInterface<ParamType>* base,
        const ParamGenerator<T1>& g1,
        const typename ParamGenerator<T1>::iterator& current1,
        const ParamGenerator<T2>& g2,
        const typename ParamGenerator<T2>::iterator& current2,
        const ParamGenerator<T3>& g3,
        const typename ParamGenerator<T3>::iterator& current3)
          : base_(base),
            begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
            begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
            begin3_(g3.begin()), end3_(g3.end()), current3_(current3)    {
        ComputeCurrentValue();
      }
      virtual ~Iterator() {}
  
      virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
        return base_;
      }
      // Advance should not be called on beyond-of-range iterators
      // so no component iterators must be beyond end of range, either.
      virtual void Advance() {
        assert(!AtEnd());
        ++current3_;
        if (current3_ == end3_) {
          current3_ = begin3_;
          ++current2_;
        }
        if (current2_ == end2_) {
          current2_ = begin2_;
          ++current1_;
        }
        ComputeCurrentValue();
      }
      virtual ParamIteratorInterface<ParamType>* Clone() const {
        return new Iterator(*this);
      }
      virtual const ParamType* Current() const { return current_value_.get(); }
      virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
        // Having the same base generator guarantees that the other
        // iterator is of the same type and we can downcast.
        GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
            << "The program attempted to compare iterators "
            << "from different generators." << std::endl;
        const Iterator* typed_other =
            CheckedDowncastToActualType<const Iterator>(&other);
        // We must report iterators equal if they both point beyond their
        // respective ranges. That can happen in a variety of fashions,
        // so we have to consult AtEnd().
        return (AtEnd() && typed_other->AtEnd()) ||
           (
            current1_ == typed_other->current1_ &&
            current2_ == typed_other->current2_ &&
            current3_ == typed_other->current3_);
      }
  
     private:
      Iterator(const Iterator& other)
          : base_(other.base_),
          begin1_(other.begin1_),
          end1_(other.end1_),
          current1_(other.current1_),
          begin2_(other.begin2_),
          end2_(other.end2_),
          current2_(other.current2_),
          begin3_(other.begin3_),
          end3_(other.end3_),
          current3_(other.current3_) {
        ComputeCurrentValue();
      }
  
      void ComputeCurrentValue() {
        if (!AtEnd())
          current_value_.reset(new ParamType(*current1_, *current2_, *current3_));
      }
      bool AtEnd() const {
        // We must report iterator past the end of the range when either of the
        // component iterators has reached the end of its range.
        return
            current1_ == end1_ ||
            current2_ == end2_ ||
            current3_ == end3_;
      }
  
      // No implementation - assignment is unsupported.
      void operator=(const Iterator& other);
  
      const ParamGeneratorInterface<ParamType>* const base_;
      // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
      // current[i]_ is the actual traversing iterator.
      const typename ParamGenerator<T1>::iterator begin1_;
      const typename ParamGenerator<T1>::iterator end1_;
      typename ParamGenerator<T1>::iterator current1_;
      const typename ParamGenerator<T2>::iterator begin2_;
      const typename ParamGenerator<T2>::iterator end2_;
      typename ParamGenerator<T2>::iterator current2_;
      const typename ParamGenerator<T3>::iterator begin3_;
      const typename ParamGenerator<T3>::iterator end3_;
      typename ParamGenerator<T3>::iterator current3_;
      std::shared_ptr<ParamType> current_value_;
    };  // class CartesianProductGenerator3::Iterator
  
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductGenerator3& other);
  
    const ParamGenerator<T1> g1_;
    const ParamGenerator<T2> g2_;
    const ParamGenerator<T3> g3_;
  };  // class CartesianProductGenerator3
  
  
  template <typename T1, typename T2, typename T3, typename T4>
  class CartesianProductGenerator4
      : public ParamGeneratorInterface< ::std::tuple<T1, T2, T3, T4> > {
   public:
    typedef ::std::tuple<T1, T2, T3, T4> ParamType;
  
    CartesianProductGenerator4(const ParamGenerator<T1>& g1,
        const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
        const ParamGenerator<T4>& g4)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
    virtual ~CartesianProductGenerator4() {}
  
    virtual ParamIteratorInterface<ParamType>* Begin() const {
      return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
          g3_.begin(), g4_, g4_.begin());
    }
    virtual ParamIteratorInterface<ParamType>* End() const {
      return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
          g4_, g4_.end());
    }
  
   private:
    class Iterator : public ParamIteratorInterface<ParamType> {
     public:
      Iterator(const ParamGeneratorInterface<ParamType>* base,
        const ParamGenerator<T1>& g1,
        const typename ParamGenerator<T1>::iterator& current1,
        const ParamGenerator<T2>& g2,
        const typename ParamGenerator<T2>::iterator& current2,
        const ParamGenerator<T3>& g3,
        const typename ParamGenerator<T3>::iterator& current3,
        const ParamGenerator<T4>& g4,
        const typename ParamGenerator<T4>::iterator& current4)
          : base_(base),
            begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
            begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
            begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
            begin4_(g4.begin()), end4_(g4.end()), current4_(current4)    {
        ComputeCurrentValue();
      }
      virtual ~Iterator() {}
  
      virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
        return base_;
      }
      // Advance should not be called on beyond-of-range iterators
      // so no component iterators must be beyond end of range, either.
      virtual void Advance() {
        assert(!AtEnd());
        ++current4_;
        if (current4_ == end4_) {
          current4_ = begin4_;
          ++current3_;
        }
        if (current3_ == end3_) {
          current3_ = begin3_;
          ++current2_;
        }
        if (current2_ == end2_) {
          current2_ = begin2_;
          ++current1_;
        }
        ComputeCurrentValue();
      }
      virtual ParamIteratorInterface<ParamType>* Clone() const {
        return new Iterator(*this);
      }
      virtual const ParamType* Current() const { return current_value_.get(); }
      virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
        // Having the same base generator guarantees that the other
        // iterator is of the same type and we can downcast.
        GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
            << "The program attempted to compare iterators "
            << "from different generators." << std::endl;
        const Iterator* typed_other =
            CheckedDowncastToActualType<const Iterator>(&other);
        // We must report iterators equal if they both point beyond their
        // respective ranges. That can happen in a variety of fashions,
        // so we have to consult AtEnd().
        return (AtEnd() && typed_other->AtEnd()) ||
           (
            current1_ == typed_other->current1_ &&
            current2_ == typed_other->current2_ &&
            current3_ == typed_other->current3_ &&
            current4_ == typed_other->current4_);
      }
  
     private:
      Iterator(const Iterator& other)
          : base_(other.base_),
          begin1_(other.begin1_),
          end1_(other.end1_),
          current1_(other.current1_),
          begin2_(other.begin2_),
          end2_(other.end2_),
          current2_(other.current2_),
          begin3_(other.begin3_),
          end3_(other.end3_),
          current3_(other.current3_),
          begin4_(other.begin4_),
          end4_(other.end4_),
          current4_(other.current4_) {
        ComputeCurrentValue();
      }
  
      void ComputeCurrentValue() {
        if (!AtEnd())
          current_value_.reset(new ParamType(*current1_, *current2_, *current3_,
              *current4_));
      }
      bool AtEnd() const {
        // We must report iterator past the end of the range when either of the
        // component iterators has reached the end of its range.
        return
            current1_ == end1_ ||
            current2_ == end2_ ||
            current3_ == end3_ ||
            current4_ == end4_;
      }
  
      // No implementation - assignment is unsupported.
      void operator=(const Iterator& other);
  
      const ParamGeneratorInterface<ParamType>* const base_;
      // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
      // current[i]_ is the actual traversing iterator.
      const typename ParamGenerator<T1>::iterator begin1_;
      const typename ParamGenerator<T1>::iterator end1_;
      typename ParamGenerator<T1>::iterator current1_;
      const typename ParamGenerator<T2>::iterator begin2_;
      const typename ParamGenerator<T2>::iterator end2_;
      typename ParamGenerator<T2>::iterator current2_;
      const typename ParamGenerator<T3>::iterator begin3_;
      const typename ParamGenerator<T3>::iterator end3_;
      typename ParamGenerator<T3>::iterator current3_;
      const typename ParamGenerator<T4>::iterator begin4_;
      const typename ParamGenerator<T4>::iterator end4_;
      typename ParamGenerator<T4>::iterator current4_;
      std::shared_ptr<ParamType> current_value_;
    };  // class CartesianProductGenerator4::Iterator
  
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductGenerator4& other);
  
    const ParamGenerator<T1> g1_;
    const ParamGenerator<T2> g2_;
    const ParamGenerator<T3> g3_;
    const ParamGenerator<T4> g4_;
  };  // class CartesianProductGenerator4
  
  
  template <typename T1, typename T2, typename T3, typename T4, typename T5>
  class CartesianProductGenerator5
      : public ParamGeneratorInterface< ::std::tuple<T1, T2, T3, T4, T5> > {
   public:
    typedef ::std::tuple<T1, T2, T3, T4, T5> ParamType;
  
    CartesianProductGenerator5(const ParamGenerator<T1>& g1,
        const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
        const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
    virtual ~CartesianProductGenerator5() {}
  
    virtual ParamIteratorInterface<ParamType>* Begin() const {
      return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
          g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
    }
    virtual ParamIteratorInterface<ParamType>* End() const {
      return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
          g4_, g4_.end(), g5_, g5_.end());
    }
  
   private:
    class Iterator : public ParamIteratorInterface<ParamType> {
     public:
      Iterator(const ParamGeneratorInterface<ParamType>* base,
        const ParamGenerator<T1>& g1,
        const typename ParamGenerator<T1>::iterator& current1,
        const ParamGenerator<T2>& g2,
        const typename ParamGenerator<T2>::iterator& current2,
        const ParamGenerator<T3>& g3,
        const typename ParamGenerator<T3>::iterator& current3,
        const ParamGenerator<T4>& g4,
        const typename ParamGenerator<T4>::iterator& current4,
        const ParamGenerator<T5>& g5,
        const typename ParamGenerator<T5>::iterator& current5)
          : base_(base),
            begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
            begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
            begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
            begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
            begin5_(g5.begin()), end5_(g5.end()), current5_(current5)    {
        ComputeCurrentValue();
      }
      virtual ~Iterator() {}
  
      virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
        return base_;
      }
      // Advance should not be called on beyond-of-range iterators
      // so no component iterators must be beyond end of range, either.
      virtual void Advance() {
        assert(!AtEnd());
        ++current5_;
        if (current5_ == end5_) {
          current5_ = begin5_;
          ++current4_;
        }
        if (current4_ == end4_) {
          current4_ = begin4_;
          ++current3_;
        }
        if (current3_ == end3_) {
          current3_ = begin3_;
          ++current2_;
        }
        if (current2_ == end2_) {
          current2_ = begin2_;
          ++current1_;
        }
        ComputeCurrentValue();
      }
      virtual ParamIteratorInterface<ParamType>* Clone() const {
        return new Iterator(*this);
      }
      virtual const ParamType* Current() const { return current_value_.get(); }
      virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
        // Having the same base generator guarantees that the other
        // iterator is of the same type and we can downcast.
        GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
            << "The program attempted to compare iterators "
            << "from different generators." << std::endl;
        const Iterator* typed_other =
            CheckedDowncastToActualType<const Iterator>(&other);
        // We must report iterators equal if they both point beyond their
        // respective ranges. That can happen in a variety of fashions,
        // so we have to consult AtEnd().
        return (AtEnd() && typed_other->AtEnd()) ||
           (
            current1_ == typed_other->current1_ &&
            current2_ == typed_other->current2_ &&
            current3_ == typed_other->current3_ &&
            current4_ == typed_other->current4_ &&
            current5_ == typed_other->current5_);
      }
  
     private:
      Iterator(const Iterator& other)
          : base_(other.base_),
          begin1_(other.begin1_),
          end1_(other.end1_),
          current1_(other.current1_),
          begin2_(other.begin2_),
          end2_(other.end2_),
          current2_(other.current2_),
          begin3_(other.begin3_),
          end3_(other.end3_),
          current3_(other.current3_),
          begin4_(other.begin4_),
          end4_(other.end4_),
          current4_(other.current4_),
          begin5_(other.begin5_),
          end5_(other.end5_),
          current5_(other.current5_) {
        ComputeCurrentValue();
      }
  
      void ComputeCurrentValue() {
        if (!AtEnd())
          current_value_.reset(new ParamType(*current1_, *current2_, *current3_,
              *current4_, *current5_));
      }
      bool AtEnd() const {
        // We must report iterator past the end of the range when either of the
        // component iterators has reached the end of its range.
        return
            current1_ == end1_ ||
            current2_ == end2_ ||
            current3_ == end3_ ||
            current4_ == end4_ ||
            current5_ == end5_;
      }
  
      // No implementation - assignment is unsupported.
      void operator=(const Iterator& other);
  
      const ParamGeneratorInterface<ParamType>* const base_;
      // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
      // current[i]_ is the actual traversing iterator.
      const typename ParamGenerator<T1>::iterator begin1_;
      const typename ParamGenerator<T1>::iterator end1_;
      typename ParamGenerator<T1>::iterator current1_;
      const typename ParamGenerator<T2>::iterator begin2_;
      const typename ParamGenerator<T2>::iterator end2_;
      typename ParamGenerator<T2>::iterator current2_;
      const typename ParamGenerator<T3>::iterator begin3_;
      const typename ParamGenerator<T3>::iterator end3_;
      typename ParamGenerator<T3>::iterator current3_;
      const typename ParamGenerator<T4>::iterator begin4_;
      const typename ParamGenerator<T4>::iterator end4_;
      typename ParamGenerator<T4>::iterator current4_;
      const typename ParamGenerator<T5>::iterator begin5_;
      const typename ParamGenerator<T5>::iterator end5_;
      typename ParamGenerator<T5>::iterator current5_;
      std::shared_ptr<ParamType> current_value_;
    };  // class CartesianProductGenerator5::Iterator
  
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductGenerator5& other);
  
    const ParamGenerator<T1> g1_;
    const ParamGenerator<T2> g2_;
    const ParamGenerator<T3> g3_;
    const ParamGenerator<T4> g4_;
    const ParamGenerator<T5> g5_;
  };  // class CartesianProductGenerator5
  
  
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6>
  class CartesianProductGenerator6
      : public ParamGeneratorInterface< ::std::tuple<T1, T2, T3, T4, T5, T6> > {
   public:
    typedef ::std::tuple<T1, T2, T3, T4, T5, T6> ParamType;
  
    CartesianProductGenerator6(const ParamGenerator<T1>& g1,
        const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
        const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
        const ParamGenerator<T6>& g6)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
    virtual ~CartesianProductGenerator6() {}
  
    virtual ParamIteratorInterface<ParamType>* Begin() const {
      return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
          g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
    }
    virtual ParamIteratorInterface<ParamType>* End() const {
      return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
          g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
    }
  
   private:
    class Iterator : public ParamIteratorInterface<ParamType> {
     public:
      Iterator(const ParamGeneratorInterface<ParamType>* base,
        const ParamGenerator<T1>& g1,
        const typename ParamGenerator<T1>::iterator& current1,
        const ParamGenerator<T2>& g2,
        const typename ParamGenerator<T2>::iterator& current2,
        const ParamGenerator<T3>& g3,
        const typename ParamGenerator<T3>::iterator& current3,
        const ParamGenerator<T4>& g4,
        const typename ParamGenerator<T4>::iterator& current4,
        const ParamGenerator<T5>& g5,
        const typename ParamGenerator<T5>::iterator& current5,
        const ParamGenerator<T6>& g6,
        const typename ParamGenerator<T6>::iterator& current6)
          : base_(base),
            begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
            begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
            begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
            begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
            begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
            begin6_(g6.begin()), end6_(g6.end()), current6_(current6)    {
        ComputeCurrentValue();
      }
      virtual ~Iterator() {}
  
      virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
        return base_;
      }
      // Advance should not be called on beyond-of-range iterators
      // so no component iterators must be beyond end of range, either.
      virtual void Advance() {
        assert(!AtEnd());
        ++current6_;
        if (current6_ == end6_) {
          current6_ = begin6_;
          ++current5_;
        }
        if (current5_ == end5_) {
          current5_ = begin5_;
          ++current4_;
        }
        if (current4_ == end4_) {
          current4_ = begin4_;
          ++current3_;
        }
        if (current3_ == end3_) {
          current3_ = begin3_;
          ++current2_;
        }
        if (current2_ == end2_) {
          current2_ = begin2_;
          ++current1_;
        }
        ComputeCurrentValue();
      }
      virtual ParamIteratorInterface<ParamType>* Clone() const {
        return new Iterator(*this);
      }
      virtual const ParamType* Current() const { return current_value_.get(); }
      virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
        // Having the same base generator guarantees that the other
        // iterator is of the same type and we can downcast.
        GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
            << "The program attempted to compare iterators "
            << "from different generators." << std::endl;
        const Iterator* typed_other =
            CheckedDowncastToActualType<const Iterator>(&other);
        // We must report iterators equal if they both point beyond their
        // respective ranges. That can happen in a variety of fashions,
        // so we have to consult AtEnd().
        return (AtEnd() && typed_other->AtEnd()) ||
           (
            current1_ == typed_other->current1_ &&
            current2_ == typed_other->current2_ &&
            current3_ == typed_other->current3_ &&
            current4_ == typed_other->current4_ &&
            current5_ == typed_other->current5_ &&
            current6_ == typed_other->current6_);
      }
  
     private:
      Iterator(const Iterator& other)
          : base_(other.base_),
          begin1_(other.begin1_),
          end1_(other.end1_),
          current1_(other.current1_),
          begin2_(other.begin2_),
          end2_(other.end2_),
          current2_(other.current2_),
          begin3_(other.begin3_),
          end3_(other.end3_),
          current3_(other.current3_),
          begin4_(other.begin4_),
          end4_(other.end4_),
          current4_(other.current4_),
          begin5_(other.begin5_),
          end5_(other.end5_),
          current5_(other.current5_),
          begin6_(other.begin6_),
          end6_(other.end6_),
          current6_(other.current6_) {
        ComputeCurrentValue();
      }
  
      void ComputeCurrentValue() {
        if (!AtEnd())
          current_value_.reset(new ParamType(*current1_, *current2_, *current3_,
              *current4_, *current5_, *current6_));
      }
      bool AtEnd() const {
        // We must report iterator past the end of the range when either of the
        // component iterators has reached the end of its range.
        return
            current1_ == end1_ ||
            current2_ == end2_ ||
            current3_ == end3_ ||
            current4_ == end4_ ||
            current5_ == end5_ ||
            current6_ == end6_;
      }
  
      // No implementation - assignment is unsupported.
      void operator=(const Iterator& other);
  
      const ParamGeneratorInterface<ParamType>* const base_;
      // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
      // current[i]_ is the actual traversing iterator.
      const typename ParamGenerator<T1>::iterator begin1_;
      const typename ParamGenerator<T1>::iterator end1_;
      typename ParamGenerator<T1>::iterator current1_;
      const typename ParamGenerator<T2>::iterator begin2_;
      const typename ParamGenerator<T2>::iterator end2_;
      typename ParamGenerator<T2>::iterator current2_;
      const typename ParamGenerator<T3>::iterator begin3_;
      const typename ParamGenerator<T3>::iterator end3_;
      typename ParamGenerator<T3>::iterator current3_;
      const typename ParamGenerator<T4>::iterator begin4_;
      const typename ParamGenerator<T4>::iterator end4_;
      typename ParamGenerator<T4>::iterator current4_;
      const typename ParamGenerator<T5>::iterator begin5_;
      const typename ParamGenerator<T5>::iterator end5_;
      typename ParamGenerator<T5>::iterator current5_;
      const typename ParamGenerator<T6>::iterator begin6_;
      const typename ParamGenerator<T6>::iterator end6_;
      typename ParamGenerator<T6>::iterator current6_;
      std::shared_ptr<ParamType> current_value_;
    };  // class CartesianProductGenerator6::Iterator
  
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductGenerator6& other);
  
    const ParamGenerator<T1> g1_;
    const ParamGenerator<T2> g2_;
    const ParamGenerator<T3> g3_;
    const ParamGenerator<T4> g4_;
    const ParamGenerator<T5> g5_;
    const ParamGenerator<T6> g6_;
  };  // class CartesianProductGenerator6
  
  
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6, typename T7>
  class CartesianProductGenerator7
      : public ParamGeneratorInterface< ::std::tuple<T1, T2, T3, T4, T5, T6,
          T7> > {
   public:
    typedef ::std::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
  
    CartesianProductGenerator7(const ParamGenerator<T1>& g1,
        const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
        const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
        const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
    virtual ~CartesianProductGenerator7() {}
  
    virtual ParamIteratorInterface<ParamType>* Begin() const {
      return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
          g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
          g7_.begin());
    }
    virtual ParamIteratorInterface<ParamType>* End() const {
      return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
          g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
    }
  
   private:
    class Iterator : public ParamIteratorInterface<ParamType> {
     public:
      Iterator(const ParamGeneratorInterface<ParamType>* base,
        const ParamGenerator<T1>& g1,
        const typename ParamGenerator<T1>::iterator& current1,
        const ParamGenerator<T2>& g2,
        const typename ParamGenerator<T2>::iterator& current2,
        const ParamGenerator<T3>& g3,
        const typename ParamGenerator<T3>::iterator& current3,
        const ParamGenerator<T4>& g4,
        const typename ParamGenerator<T4>::iterator& current4,
        const ParamGenerator<T5>& g5,
        const typename ParamGenerator<T5>::iterator& current5,
        const ParamGenerator<T6>& g6,
        const typename ParamGenerator<T6>::iterator& current6,
        const ParamGenerator<T7>& g7,
        const typename ParamGenerator<T7>::iterator& current7)
          : base_(base),
            begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
            begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
            begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
            begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
            begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
            begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
            begin7_(g7.begin()), end7_(g7.end()), current7_(current7)    {
        ComputeCurrentValue();
      }
      virtual ~Iterator() {}
  
      virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
        return base_;
      }
      // Advance should not be called on beyond-of-range iterators
      // so no component iterators must be beyond end of range, either.
      virtual void Advance() {
        assert(!AtEnd());
        ++current7_;
        if (current7_ == end7_) {
          current7_ = begin7_;
          ++current6_;
        }
        if (current6_ == end6_) {
          current6_ = begin6_;
          ++current5_;
        }
        if (current5_ == end5_) {
          current5_ = begin5_;
          ++current4_;
        }
        if (current4_ == end4_) {
          current4_ = begin4_;
          ++current3_;
        }
        if (current3_ == end3_) {
          current3_ = begin3_;
          ++current2_;
        }
        if (current2_ == end2_) {
          current2_ = begin2_;
          ++current1_;
        }
        ComputeCurrentValue();
      }
      virtual ParamIteratorInterface<ParamType>* Clone() const {
        return new Iterator(*this);
      }
      virtual const ParamType* Current() const { return current_value_.get(); }
      virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
        // Having the same base generator guarantees that the other
        // iterator is of the same type and we can downcast.
        GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
            << "The program attempted to compare iterators "
            << "from different generators." << std::endl;
        const Iterator* typed_other =
            CheckedDowncastToActualType<const Iterator>(&other);
        // We must report iterators equal if they both point beyond their
        // respective ranges. That can happen in a variety of fashions,
        // so we have to consult AtEnd().
        return (AtEnd() && typed_other->AtEnd()) ||
           (
            current1_ == typed_other->current1_ &&
            current2_ == typed_other->current2_ &&
            current3_ == typed_other->current3_ &&
            current4_ == typed_other->current4_ &&
            current5_ == typed_other->current5_ &&
            current6_ == typed_other->current6_ &&
            current7_ == typed_other->current7_);
      }
  
     private:
      Iterator(const Iterator& other)
          : base_(other.base_),
          begin1_(other.begin1_),
          end1_(other.end1_),
          current1_(other.current1_),
          begin2_(other.begin2_),
          end2_(other.end2_),
          current2_(other.current2_),
          begin3_(other.begin3_),
          end3_(other.end3_),
          current3_(other.current3_),
          begin4_(other.begin4_),
          end4_(other.end4_),
          current4_(other.current4_),
          begin5_(other.begin5_),
          end5_(other.end5_),
          current5_(other.current5_),
          begin6_(other.begin6_),
          end6_(other.end6_),
          current6_(other.current6_),
          begin7_(other.begin7_),
          end7_(other.end7_),
          current7_(other.current7_) {
        ComputeCurrentValue();
      }
  
      void ComputeCurrentValue() {
        if (!AtEnd())
          current_value_.reset(new ParamType(*current1_, *current2_, *current3_,
              *current4_, *current5_, *current6_, *current7_));
      }
      bool AtEnd() const {
        // We must report iterator past the end of the range when either of the
        // component iterators has reached the end of its range.
        return
            current1_ == end1_ ||
            current2_ == end2_ ||
            current3_ == end3_ ||
            current4_ == end4_ ||
            current5_ == end5_ ||
            current6_ == end6_ ||
            current7_ == end7_;
      }
  
      // No implementation - assignment is unsupported.
      void operator=(const Iterator& other);
  
      const ParamGeneratorInterface<ParamType>* const base_;
      // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
      // current[i]_ is the actual traversing iterator.
      const typename ParamGenerator<T1>::iterator begin1_;
      const typename ParamGenerator<T1>::iterator end1_;
      typename ParamGenerator<T1>::iterator current1_;
      const typename ParamGenerator<T2>::iterator begin2_;
      const typename ParamGenerator<T2>::iterator end2_;
      typename ParamGenerator<T2>::iterator current2_;
      const typename ParamGenerator<T3>::iterator begin3_;
      const typename ParamGenerator<T3>::iterator end3_;
      typename ParamGenerator<T3>::iterator current3_;
      const typename ParamGenerator<T4>::iterator begin4_;
      const typename ParamGenerator<T4>::iterator end4_;
      typename ParamGenerator<T4>::iterator current4_;
      const typename ParamGenerator<T5>::iterator begin5_;
      const typename ParamGenerator<T5>::iterator end5_;
      typename ParamGenerator<T5>::iterator current5_;
      const typename ParamGenerator<T6>::iterator begin6_;
      const typename ParamGenerator<T6>::iterator end6_;
      typename ParamGenerator<T6>::iterator current6_;
      const typename ParamGenerator<T7>::iterator begin7_;
      const typename ParamGenerator<T7>::iterator end7_;
      typename ParamGenerator<T7>::iterator current7_;
      std::shared_ptr<ParamType> current_value_;
    };  // class CartesianProductGenerator7::Iterator
  
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductGenerator7& other);
  
    const ParamGenerator<T1> g1_;
    const ParamGenerator<T2> g2_;
    const ParamGenerator<T3> g3_;
    const ParamGenerator<T4> g4_;
    const ParamGenerator<T5> g5_;
    const ParamGenerator<T6> g6_;
    const ParamGenerator<T7> g7_;
  };  // class CartesianProductGenerator7
  
  
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6, typename T7, typename T8>
  class CartesianProductGenerator8
      : public ParamGeneratorInterface< ::std::tuple<T1, T2, T3, T4, T5, T6, T7,
          T8> > {
   public:
    typedef ::std::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
  
    CartesianProductGenerator8(const ParamGenerator<T1>& g1,
        const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
        const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
        const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
        const ParamGenerator<T8>& g8)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
            g8_(g8) {}
    virtual ~CartesianProductGenerator8() {}
  
    virtual ParamIteratorInterface<ParamType>* Begin() const {
      return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
          g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
          g7_.begin(), g8_, g8_.begin());
    }
    virtual ParamIteratorInterface<ParamType>* End() const {
      return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
          g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
          g8_.end());
    }
  
   private:
    class Iterator : public ParamIteratorInterface<ParamType> {
     public:
      Iterator(const ParamGeneratorInterface<ParamType>* base,
        const ParamGenerator<T1>& g1,
        const typename ParamGenerator<T1>::iterator& current1,
        const ParamGenerator<T2>& g2,
        const typename ParamGenerator<T2>::iterator& current2,
        const ParamGenerator<T3>& g3,
        const typename ParamGenerator<T3>::iterator& current3,
        const ParamGenerator<T4>& g4,
        const typename ParamGenerator<T4>::iterator& current4,
        const ParamGenerator<T5>& g5,
        const typename ParamGenerator<T5>::iterator& current5,
        const ParamGenerator<T6>& g6,
        const typename ParamGenerator<T6>::iterator& current6,
        const ParamGenerator<T7>& g7,
        const typename ParamGenerator<T7>::iterator& current7,
        const ParamGenerator<T8>& g8,
        const typename ParamGenerator<T8>::iterator& current8)
          : base_(base),
            begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
            begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
            begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
            begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
            begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
            begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
            begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
            begin8_(g8.begin()), end8_(g8.end()), current8_(current8)    {
        ComputeCurrentValue();
      }
      virtual ~Iterator() {}
  
      virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
        return base_;
      }
      // Advance should not be called on beyond-of-range iterators
      // so no component iterators must be beyond end of range, either.
      virtual void Advance() {
        assert(!AtEnd());
        ++current8_;
        if (current8_ == end8_) {
          current8_ = begin8_;
          ++current7_;
        }
        if (current7_ == end7_) {
          current7_ = begin7_;
          ++current6_;
        }
        if (current6_ == end6_) {
          current6_ = begin6_;
          ++current5_;
        }
        if (current5_ == end5_) {
          current5_ = begin5_;
          ++current4_;
        }
        if (current4_ == end4_) {
          current4_ = begin4_;
          ++current3_;
        }
        if (current3_ == end3_) {
          current3_ = begin3_;
          ++current2_;
        }
        if (current2_ == end2_) {
          current2_ = begin2_;
          ++current1_;
        }
        ComputeCurrentValue();
      }
      virtual ParamIteratorInterface<ParamType>* Clone() const {
        return new Iterator(*this);
      }
      virtual const ParamType* Current() const { return current_value_.get(); }
      virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
        // Having the same base generator guarantees that the other
        // iterator is of the same type and we can downcast.
        GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
            << "The program attempted to compare iterators "
            << "from different generators." << std::endl;
        const Iterator* typed_other =
            CheckedDowncastToActualType<const Iterator>(&other);
        // We must report iterators equal if they both point beyond their
        // respective ranges. That can happen in a variety of fashions,
        // so we have to consult AtEnd().
        return (AtEnd() && typed_other->AtEnd()) ||
           (
            current1_ == typed_other->current1_ &&
            current2_ == typed_other->current2_ &&
            current3_ == typed_other->current3_ &&
            current4_ == typed_other->current4_ &&
            current5_ == typed_other->current5_ &&
            current6_ == typed_other->current6_ &&
            current7_ == typed_other->current7_ &&
            current8_ == typed_other->current8_);
      }
  
     private:
      Iterator(const Iterator& other)
          : base_(other.base_),
          begin1_(other.begin1_),
          end1_(other.end1_),
          current1_(other.current1_),
          begin2_(other.begin2_),
          end2_(other.end2_),
          current2_(other.current2_),
          begin3_(other.begin3_),
          end3_(other.end3_),
          current3_(other.current3_),
          begin4_(other.begin4_),
          end4_(other.end4_),
          current4_(other.current4_),
          begin5_(other.begin5_),
          end5_(other.end5_),
          current5_(other.current5_),
          begin6_(other.begin6_),
          end6_(other.end6_),
          current6_(other.current6_),
          begin7_(other.begin7_),
          end7_(other.end7_),
          current7_(other.current7_),
          begin8_(other.begin8_),
          end8_(other.end8_),
          current8_(other.current8_) {
        ComputeCurrentValue();
      }
  
      void ComputeCurrentValue() {
        if (!AtEnd())
          current_value_.reset(new ParamType(*current1_, *current2_, *current3_,
              *current4_, *current5_, *current6_, *current7_, *current8_));
      }
      bool AtEnd() const {
        // We must report iterator past the end of the range when either of the
        // component iterators has reached the end of its range.
        return
            current1_ == end1_ ||
            current2_ == end2_ ||
            current3_ == end3_ ||
            current4_ == end4_ ||
            current5_ == end5_ ||
            current6_ == end6_ ||
            current7_ == end7_ ||
            current8_ == end8_;
      }
  
      // No implementation - assignment is unsupported.
      void operator=(const Iterator& other);
  
      const ParamGeneratorInterface<ParamType>* const base_;
      // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
      // current[i]_ is the actual traversing iterator.
      const typename ParamGenerator<T1>::iterator begin1_;
      const typename ParamGenerator<T1>::iterator end1_;
      typename ParamGenerator<T1>::iterator current1_;
      const typename ParamGenerator<T2>::iterator begin2_;
      const typename ParamGenerator<T2>::iterator end2_;
      typename ParamGenerator<T2>::iterator current2_;
      const typename ParamGenerator<T3>::iterator begin3_;
      const typename ParamGenerator<T3>::iterator end3_;
      typename ParamGenerator<T3>::iterator current3_;
      const typename ParamGenerator<T4>::iterator begin4_;
      const typename ParamGenerator<T4>::iterator end4_;
      typename ParamGenerator<T4>::iterator current4_;
      const typename ParamGenerator<T5>::iterator begin5_;
      const typename ParamGenerator<T5>::iterator end5_;
      typename ParamGenerator<T5>::iterator current5_;
      const typename ParamGenerator<T6>::iterator begin6_;
      const typename ParamGenerator<T6>::iterator end6_;
      typename ParamGenerator<T6>::iterator current6_;
      const typename ParamGenerator<T7>::iterator begin7_;
      const typename ParamGenerator<T7>::iterator end7_;
      typename ParamGenerator<T7>::iterator current7_;
      const typename ParamGenerator<T8>::iterator begin8_;
      const typename ParamGenerator<T8>::iterator end8_;
      typename ParamGenerator<T8>::iterator current8_;
      std::shared_ptr<ParamType> current_value_;
    };  // class CartesianProductGenerator8::Iterator
  
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductGenerator8& other);
  
    const ParamGenerator<T1> g1_;
    const ParamGenerator<T2> g2_;
    const ParamGenerator<T3> g3_;
    const ParamGenerator<T4> g4_;
    const ParamGenerator<T5> g5_;
    const ParamGenerator<T6> g6_;
    const ParamGenerator<T7> g7_;
    const ParamGenerator<T8> g8_;
  };  // class CartesianProductGenerator8
  
  
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6, typename T7, typename T8, typename T9>
  class CartesianProductGenerator9
      : public ParamGeneratorInterface< ::std::tuple<T1, T2, T3, T4, T5, T6, T7,
          T8, T9> > {
   public:
    typedef ::std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
  
    CartesianProductGenerator9(const ParamGenerator<T1>& g1,
        const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
        const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
        const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
        const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
            g9_(g9) {}
    virtual ~CartesianProductGenerator9() {}
  
    virtual ParamIteratorInterface<ParamType>* Begin() const {
      return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
          g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
          g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
    }
    virtual ParamIteratorInterface<ParamType>* End() const {
      return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
          g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
          g8_.end(), g9_, g9_.end());
    }
  
   private:
    class Iterator : public ParamIteratorInterface<ParamType> {
     public:
      Iterator(const ParamGeneratorInterface<ParamType>* base,
        const ParamGenerator<T1>& g1,
        const typename ParamGenerator<T1>::iterator& current1,
        const ParamGenerator<T2>& g2,
        const typename ParamGenerator<T2>::iterator& current2,
        const ParamGenerator<T3>& g3,
        const typename ParamGenerator<T3>::iterator& current3,
        const ParamGenerator<T4>& g4,
        const typename ParamGenerator<T4>::iterator& current4,
        const ParamGenerator<T5>& g5,
        const typename ParamGenerator<T5>::iterator& current5,
        const ParamGenerator<T6>& g6,
        const typename ParamGenerator<T6>::iterator& current6,
        const ParamGenerator<T7>& g7,
        const typename ParamGenerator<T7>::iterator& current7,
        const ParamGenerator<T8>& g8,
        const typename ParamGenerator<T8>::iterator& current8,
        const ParamGenerator<T9>& g9,
        const typename ParamGenerator<T9>::iterator& current9)
          : base_(base),
            begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
            begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
            begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
            begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
            begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
            begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
            begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
            begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
            begin9_(g9.begin()), end9_(g9.end()), current9_(current9)    {
        ComputeCurrentValue();
      }
      virtual ~Iterator() {}
  
      virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
        return base_;
      }
      // Advance should not be called on beyond-of-range iterators
      // so no component iterators must be beyond end of range, either.
      virtual void Advance() {
        assert(!AtEnd());
        ++current9_;
        if (current9_ == end9_) {
          current9_ = begin9_;
          ++current8_;
        }
        if (current8_ == end8_) {
          current8_ = begin8_;
          ++current7_;
        }
        if (current7_ == end7_) {
          current7_ = begin7_;
          ++current6_;
        }
        if (current6_ == end6_) {
          current6_ = begin6_;
          ++current5_;
        }
        if (current5_ == end5_) {
          current5_ = begin5_;
          ++current4_;
        }
        if (current4_ == end4_) {
          current4_ = begin4_;
          ++current3_;
        }
        if (current3_ == end3_) {
          current3_ = begin3_;
          ++current2_;
        }
        if (current2_ == end2_) {
          current2_ = begin2_;
          ++current1_;
        }
        ComputeCurrentValue();
      }
      virtual ParamIteratorInterface<ParamType>* Clone() const {
        return new Iterator(*this);
      }
      virtual const ParamType* Current() const { return current_value_.get(); }
      virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
        // Having the same base generator guarantees that the other
        // iterator is of the same type and we can downcast.
        GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
            << "The program attempted to compare iterators "
            << "from different generators." << std::endl;
        const Iterator* typed_other =
            CheckedDowncastToActualType<const Iterator>(&other);
        // We must report iterators equal if they both point beyond their
        // respective ranges. That can happen in a variety of fashions,
        // so we have to consult AtEnd().
        return (AtEnd() && typed_other->AtEnd()) ||
           (
            current1_ == typed_other->current1_ &&
            current2_ == typed_other->current2_ &&
            current3_ == typed_other->current3_ &&
            current4_ == typed_other->current4_ &&
            current5_ == typed_other->current5_ &&
            current6_ == typed_other->current6_ &&
            current7_ == typed_other->current7_ &&
            current8_ == typed_other->current8_ &&
            current9_ == typed_other->current9_);
      }
  
     private:
      Iterator(const Iterator& other)
          : base_(other.base_),
          begin1_(other.begin1_),
          end1_(other.end1_),
          current1_(other.current1_),
          begin2_(other.begin2_),
          end2_(other.end2_),
          current2_(other.current2_),
          begin3_(other.begin3_),
          end3_(other.end3_),
          current3_(other.current3_),
          begin4_(other.begin4_),
          end4_(other.end4_),
          current4_(other.current4_),
          begin5_(other.begin5_),
          end5_(other.end5_),
          current5_(other.current5_),
          begin6_(other.begin6_),
          end6_(other.end6_),
          current6_(other.current6_),
          begin7_(other.begin7_),
          end7_(other.end7_),
          current7_(other.current7_),
          begin8_(other.begin8_),
          end8_(other.end8_),
          current8_(other.current8_),
          begin9_(other.begin9_),
          end9_(other.end9_),
          current9_(other.current9_) {
        ComputeCurrentValue();
      }
  
      void ComputeCurrentValue() {
        if (!AtEnd())
          current_value_.reset(new ParamType(*current1_, *current2_, *current3_,
              *current4_, *current5_, *current6_, *current7_, *current8_,
              *current9_));
      }
      bool AtEnd() const {
        // We must report iterator past the end of the range when either of the
        // component iterators has reached the end of its range.
        return
            current1_ == end1_ ||
            current2_ == end2_ ||
            current3_ == end3_ ||
            current4_ == end4_ ||
            current5_ == end5_ ||
            current6_ == end6_ ||
            current7_ == end7_ ||
            current8_ == end8_ ||
            current9_ == end9_;
      }
  
      // No implementation - assignment is unsupported.
      void operator=(const Iterator& other);
  
      const ParamGeneratorInterface<ParamType>* const base_;
      // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
      // current[i]_ is the actual traversing iterator.
      const typename ParamGenerator<T1>::iterator begin1_;
      const typename ParamGenerator<T1>::iterator end1_;
      typename ParamGenerator<T1>::iterator current1_;
      const typename ParamGenerator<T2>::iterator begin2_;
      const typename ParamGenerator<T2>::iterator end2_;
      typename ParamGenerator<T2>::iterator current2_;
      const typename ParamGenerator<T3>::iterator begin3_;
      const typename ParamGenerator<T3>::iterator end3_;
      typename ParamGenerator<T3>::iterator current3_;
      const typename ParamGenerator<T4>::iterator begin4_;
      const typename ParamGenerator<T4>::iterator end4_;
      typename ParamGenerator<T4>::iterator current4_;
      const typename ParamGenerator<T5>::iterator begin5_;
      const typename ParamGenerator<T5>::iterator end5_;
      typename ParamGenerator<T5>::iterator current5_;
      const typename ParamGenerator<T6>::iterator begin6_;
      const typename ParamGenerator<T6>::iterator end6_;
      typename ParamGenerator<T6>::iterator current6_;
      const typename ParamGenerator<T7>::iterator begin7_;
      const typename ParamGenerator<T7>::iterator end7_;
      typename ParamGenerator<T7>::iterator current7_;
      const typename ParamGenerator<T8>::iterator begin8_;
      const typename ParamGenerator<T8>::iterator end8_;
      typename ParamGenerator<T8>::iterator current8_;
      const typename ParamGenerator<T9>::iterator begin9_;
      const typename ParamGenerator<T9>::iterator end9_;
      typename ParamGenerator<T9>::iterator current9_;
      std::shared_ptr<ParamType> current_value_;
    };  // class CartesianProductGenerator9::Iterator
  
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductGenerator9& other);
  
    const ParamGenerator<T1> g1_;
    const ParamGenerator<T2> g2_;
    const ParamGenerator<T3> g3_;
    const ParamGenerator<T4> g4_;
    const ParamGenerator<T5> g5_;
    const ParamGenerator<T6> g6_;
    const ParamGenerator<T7> g7_;
    const ParamGenerator<T8> g8_;
    const ParamGenerator<T9> g9_;
  };  // class CartesianProductGenerator9
  
  
  template <typename T1, typename T2, typename T3, typename T4, typename T5,
      typename T6, typename T7, typename T8, typename T9, typename T10>
  class CartesianProductGenerator10
      : public ParamGeneratorInterface< ::std::tuple<T1, T2, T3, T4, T5, T6, T7,
          T8, T9, T10> > {
   public:
    typedef ::std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
  
    CartesianProductGenerator10(const ParamGenerator<T1>& g1,
        const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
        const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
        const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
        const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
        const ParamGenerator<T10>& g10)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
            g9_(g9), g10_(g10) {}
    virtual ~CartesianProductGenerator10() {}
  
    virtual ParamIteratorInterface<ParamType>* Begin() const {
      return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
          g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
          g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
    }
    virtual ParamIteratorInterface<ParamType>* End() const {
      return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
          g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
          g8_.end(), g9_, g9_.end(), g10_, g10_.end());
    }
  
   private:
    class Iterator : public ParamIteratorInterface<ParamType> {
     public:
      Iterator(const ParamGeneratorInterface<ParamType>* base,
        const ParamGenerator<T1>& g1,
        const typename ParamGenerator<T1>::iterator& current1,
        const ParamGenerator<T2>& g2,
        const typename ParamGenerator<T2>::iterator& current2,
        const ParamGenerator<T3>& g3,
        const typename ParamGenerator<T3>::iterator& current3,
        const ParamGenerator<T4>& g4,
        const typename ParamGenerator<T4>::iterator& current4,
        const ParamGenerator<T5>& g5,
        const typename ParamGenerator<T5>::iterator& current5,
        const ParamGenerator<T6>& g6,
        const typename ParamGenerator<T6>::iterator& current6,
        const ParamGenerator<T7>& g7,
        const typename ParamGenerator<T7>::iterator& current7,
        const ParamGenerator<T8>& g8,
        const typename ParamGenerator<T8>::iterator& current8,
        const ParamGenerator<T9>& g9,
        const typename ParamGenerator<T9>::iterator& current9,
        const ParamGenerator<T10>& g10,
        const typename ParamGenerator<T10>::iterator& current10)
          : base_(base),
            begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
            begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
            begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
            begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
            begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
            begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
            begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
            begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
            begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
            begin10_(g10.begin()), end10_(g10.end()), current10_(current10)    {
        ComputeCurrentValue();
      }
      virtual ~Iterator() {}
  
      virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
        return base_;
      }
      // Advance should not be called on beyond-of-range iterators
      // so no component iterators must be beyond end of range, either.
      virtual void Advance() {
        assert(!AtEnd());
        ++current10_;
        if (current10_ == end10_) {
          current10_ = begin10_;
          ++current9_;
        }
        if (current9_ == end9_) {
          current9_ = begin9_;
          ++current8_;
        }
        if (current8_ == end8_) {
          current8_ = begin8_;
          ++current7_;
        }
        if (current7_ == end7_) {
          current7_ = begin7_;
          ++current6_;
        }
        if (current6_ == end6_) {
          current6_ = begin6_;
          ++current5_;
        }
        if (current5_ == end5_) {
          current5_ = begin5_;
          ++current4_;
        }
        if (current4_ == end4_) {
          current4_ = begin4_;
          ++current3_;
        }
        if (current3_ == end3_) {
          current3_ = begin3_;
          ++current2_;
        }
        if (current2_ == end2_) {
          current2_ = begin2_;
          ++current1_;
        }
        ComputeCurrentValue();
      }
      virtual ParamIteratorInterface<ParamType>* Clone() const {
        return new Iterator(*this);
      }
      virtual const ParamType* Current() const { return current_value_.get(); }
      virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
        // Having the same base generator guarantees that the other
        // iterator is of the same type and we can downcast.
        GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
            << "The program attempted to compare iterators "
            << "from different generators." << std::endl;
        const Iterator* typed_other =
            CheckedDowncastToActualType<const Iterator>(&other);
        // We must report iterators equal if they both point beyond their
        // respective ranges. That can happen in a variety of fashions,
        // so we have to consult AtEnd().
        return (AtEnd() && typed_other->AtEnd()) ||
           (
            current1_ == typed_other->current1_ &&
            current2_ == typed_other->current2_ &&
            current3_ == typed_other->current3_ &&
            current4_ == typed_other->current4_ &&
            current5_ == typed_other->current5_ &&
            current6_ == typed_other->current6_ &&
            current7_ == typed_other->current7_ &&
            current8_ == typed_other->current8_ &&
            current9_ == typed_other->current9_ &&
            current10_ == typed_other->current10_);
      }
  
     private:
      Iterator(const Iterator& other)
          : base_(other.base_),
          begin1_(other.begin1_),
          end1_(other.end1_),
          current1_(other.current1_),
          begin2_(other.begin2_),
          end2_(other.end2_),
          current2_(other.current2_),
          begin3_(other.begin3_),
          end3_(other.end3_),
          current3_(other.current3_),
          begin4_(other.begin4_),
          end4_(other.end4_),
          current4_(other.current4_),
          begin5_(other.begin5_),
          end5_(other.end5_),
          current5_(other.current5_),
          begin6_(other.begin6_),
          end6_(other.end6_),
          current6_(other.current6_),
          begin7_(other.begin7_),
          end7_(other.end7_),
          current7_(other.current7_),
          begin8_(other.begin8_),
          end8_(other.end8_),
          current8_(other.current8_),
          begin9_(other.begin9_),
          end9_(other.end9_),
          current9_(other.current9_),
          begin10_(other.begin10_),
          end10_(other.end10_),
          current10_(other.current10_) {
        ComputeCurrentValue();
      }
  
      void ComputeCurrentValue() {
        if (!AtEnd())
          current_value_.reset(new ParamType(*current1_, *current2_, *current3_,
              *current4_, *current5_, *current6_, *current7_, *current8_,
              *current9_, *current10_));
      }
      bool AtEnd() const {
        // We must report iterator past the end of the range when either of the
        // component iterators has reached the end of its range.
        return
            current1_ == end1_ ||
            current2_ == end2_ ||
            current3_ == end3_ ||
            current4_ == end4_ ||
            current5_ == end5_ ||
            current6_ == end6_ ||
            current7_ == end7_ ||
            current8_ == end8_ ||
            current9_ == end9_ ||
            current10_ == end10_;
      }
  
      // No implementation - assignment is unsupported.
      void operator=(const Iterator& other);
  
      const ParamGeneratorInterface<ParamType>* const base_;
      // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
      // current[i]_ is the actual traversing iterator.
      const typename ParamGenerator<T1>::iterator begin1_;
      const typename ParamGenerator<T1>::iterator end1_;
      typename ParamGenerator<T1>::iterator current1_;
      const typename ParamGenerator<T2>::iterator begin2_;
      const typename ParamGenerator<T2>::iterator end2_;
      typename ParamGenerator<T2>::iterator current2_;
      const typename ParamGenerator<T3>::iterator begin3_;
      const typename ParamGenerator<T3>::iterator end3_;
      typename ParamGenerator<T3>::iterator current3_;
      const typename ParamGenerator<T4>::iterator begin4_;
      const typename ParamGenerator<T4>::iterator end4_;
      typename ParamGenerator<T4>::iterator current4_;
      const typename ParamGenerator<T5>::iterator begin5_;
      const typename ParamGenerator<T5>::iterator end5_;
      typename ParamGenerator<T5>::iterator current5_;
      const typename ParamGenerator<T6>::iterator begin6_;
      const typename ParamGenerator<T6>::iterator end6_;
      typename ParamGenerator<T6>::iterator current6_;
      const typename ParamGenerator<T7>::iterator begin7_;
      const typename ParamGenerator<T7>::iterator end7_;
      typename ParamGenerator<T7>::iterator current7_;
      const typename ParamGenerator<T8>::iterator begin8_;
      const typename ParamGenerator<T8>::iterator end8_;
      typename ParamGenerator<T8>::iterator current8_;
      const typename ParamGenerator<T9>::iterator begin9_;
      const typename ParamGenerator<T9>::iterator end9_;
      typename ParamGenerator<T9>::iterator current9_;
      const typename ParamGenerator<T10>::iterator begin10_;
      const typename ParamGenerator<T10>::iterator end10_;
      typename ParamGenerator<T10>::iterator current10_;
      std::shared_ptr<ParamType> current_value_;
    };  // class CartesianProductGenerator10::Iterator
  
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductGenerator10& other);
  
    const ParamGenerator<T1> g1_;
    const ParamGenerator<T2> g2_;
    const ParamGenerator<T3> g3_;
    const ParamGenerator<T4> g4_;
    const ParamGenerator<T5> g5_;
    const ParamGenerator<T6> g6_;
    const ParamGenerator<T7> g7_;
    const ParamGenerator<T8> g8_;
    const ParamGenerator<T9> g9_;
    const ParamGenerator<T10> g10_;
  };  // class CartesianProductGenerator10
  
  
  // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
  //
  // Helper classes providing Combine() with polymorphic features. They allow
  // casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
  // convertible to U.
  //
  template <class Generator1, class Generator2>
  class CartesianProductHolder2 {
   public:
  CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
        : g1_(g1), g2_(g2) {}
    template <typename T1, typename T2>
    operator ParamGenerator< ::std::tuple<T1, T2> >() const {
      return ParamGenerator< ::std::tuple<T1, T2> >(
          new CartesianProductGenerator2<T1, T2>(
          static_cast<ParamGenerator<T1> >(g1_),
          static_cast<ParamGenerator<T2> >(g2_)));
    }
  
   private:
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductHolder2& other);
  
    const Generator1 g1_;
    const Generator2 g2_;
  };  // class CartesianProductHolder2
  
  template <class Generator1, class Generator2, class Generator3>
  class CartesianProductHolder3 {
   public:
  CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
      const Generator3& g3)
        : g1_(g1), g2_(g2), g3_(g3) {}
    template <typename T1, typename T2, typename T3>
    operator ParamGenerator< ::std::tuple<T1, T2, T3> >() const {
      return ParamGenerator< ::std::tuple<T1, T2, T3> >(
          new CartesianProductGenerator3<T1, T2, T3>(
          static_cast<ParamGenerator<T1> >(g1_),
          static_cast<ParamGenerator<T2> >(g2_),
          static_cast<ParamGenerator<T3> >(g3_)));
    }
  
   private:
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductHolder3& other);
  
    const Generator1 g1_;
    const Generator2 g2_;
    const Generator3 g3_;
  };  // class CartesianProductHolder3
  
  template <class Generator1, class Generator2, class Generator3,
      class Generator4>
  class CartesianProductHolder4 {
   public:
  CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
      const Generator3& g3, const Generator4& g4)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
    template <typename T1, typename T2, typename T3, typename T4>
    operator ParamGenerator< ::std::tuple<T1, T2, T3, T4> >() const {
      return ParamGenerator< ::std::tuple<T1, T2, T3, T4> >(
          new CartesianProductGenerator4<T1, T2, T3, T4>(
          static_cast<ParamGenerator<T1> >(g1_),
          static_cast<ParamGenerator<T2> >(g2_),
          static_cast<ParamGenerator<T3> >(g3_),
          static_cast<ParamGenerator<T4> >(g4_)));
    }
  
   private:
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductHolder4& other);
  
    const Generator1 g1_;
    const Generator2 g2_;
    const Generator3 g3_;
    const Generator4 g4_;
  };  // class CartesianProductHolder4
  
  template <class Generator1, class Generator2, class Generator3,
      class Generator4, class Generator5>
  class CartesianProductHolder5 {
   public:
  CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
      const Generator3& g3, const Generator4& g4, const Generator5& g5)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
    template <typename T1, typename T2, typename T3, typename T4, typename T5>
    operator ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5> >() const {
      return ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5> >(
          new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
          static_cast<ParamGenerator<T1> >(g1_),
          static_cast<ParamGenerator<T2> >(g2_),
          static_cast<ParamGenerator<T3> >(g3_),
          static_cast<ParamGenerator<T4> >(g4_),
          static_cast<ParamGenerator<T5> >(g5_)));
    }
  
   private:
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductHolder5& other);
  
    const Generator1 g1_;
    const Generator2 g2_;
    const Generator3 g3_;
    const Generator4 g4_;
    const Generator5 g5_;
  };  // class CartesianProductHolder5
  
  template <class Generator1, class Generator2, class Generator3,
      class Generator4, class Generator5, class Generator6>
  class CartesianProductHolder6 {
   public:
  CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
      const Generator3& g3, const Generator4& g4, const Generator5& g5,
      const Generator6& g6)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
    template <typename T1, typename T2, typename T3, typename T4, typename T5,
        typename T6>
    operator ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6> >() const {
      return ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6> >(
          new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
          static_cast<ParamGenerator<T1> >(g1_),
          static_cast<ParamGenerator<T2> >(g2_),
          static_cast<ParamGenerator<T3> >(g3_),
          static_cast<ParamGenerator<T4> >(g4_),
          static_cast<ParamGenerator<T5> >(g5_),
          static_cast<ParamGenerator<T6> >(g6_)));
    }
  
   private:
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductHolder6& other);
  
    const Generator1 g1_;
    const Generator2 g2_;
    const Generator3 g3_;
    const Generator4 g4_;
    const Generator5 g5_;
    const Generator6 g6_;
  };  // class CartesianProductHolder6
  
  template <class Generator1, class Generator2, class Generator3,
      class Generator4, class Generator5, class Generator6, class Generator7>
  class CartesianProductHolder7 {
   public:
  CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
      const Generator3& g3, const Generator4& g4, const Generator5& g5,
      const Generator6& g6, const Generator7& g7)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
    template <typename T1, typename T2, typename T3, typename T4, typename T5,
        typename T6, typename T7>
    operator ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6, T7> >() const {
      return ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6, T7> >(
          new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
          static_cast<ParamGenerator<T1> >(g1_),
          static_cast<ParamGenerator<T2> >(g2_),
          static_cast<ParamGenerator<T3> >(g3_),
          static_cast<ParamGenerator<T4> >(g4_),
          static_cast<ParamGenerator<T5> >(g5_),
          static_cast<ParamGenerator<T6> >(g6_),
          static_cast<ParamGenerator<T7> >(g7_)));
    }
  
   private:
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductHolder7& other);
  
    const Generator1 g1_;
    const Generator2 g2_;
    const Generator3 g3_;
    const Generator4 g4_;
    const Generator5 g5_;
    const Generator6 g6_;
    const Generator7 g7_;
  };  // class CartesianProductHolder7
  
  template <class Generator1, class Generator2, class Generator3,
      class Generator4, class Generator5, class Generator6, class Generator7,
      class Generator8>
  class CartesianProductHolder8 {
   public:
  CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
      const Generator3& g3, const Generator4& g4, const Generator5& g5,
      const Generator6& g6, const Generator7& g7, const Generator8& g8)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
            g8_(g8) {}
    template <typename T1, typename T2, typename T3, typename T4, typename T5,
        typename T6, typename T7, typename T8>
    operator ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6, T7,
        T8> >() const {
      return ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
          new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
          static_cast<ParamGenerator<T1> >(g1_),
          static_cast<ParamGenerator<T2> >(g2_),
          static_cast<ParamGenerator<T3> >(g3_),
          static_cast<ParamGenerator<T4> >(g4_),
          static_cast<ParamGenerator<T5> >(g5_),
          static_cast<ParamGenerator<T6> >(g6_),
          static_cast<ParamGenerator<T7> >(g7_),
          static_cast<ParamGenerator<T8> >(g8_)));
    }
  
   private:
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductHolder8& other);
  
    const Generator1 g1_;
    const Generator2 g2_;
    const Generator3 g3_;
    const Generator4 g4_;
    const Generator5 g5_;
    const Generator6 g6_;
    const Generator7 g7_;
    const Generator8 g8_;
  };  // class CartesianProductHolder8
  
  template <class Generator1, class Generator2, class Generator3,
      class Generator4, class Generator5, class Generator6, class Generator7,
      class Generator8, class Generator9>
  class CartesianProductHolder9 {
   public:
  CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
      const Generator3& g3, const Generator4& g4, const Generator5& g5,
      const Generator6& g6, const Generator7& g7, const Generator8& g8,
      const Generator9& g9)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
            g9_(g9) {}
    template <typename T1, typename T2, typename T3, typename T4, typename T5,
        typename T6, typename T7, typename T8, typename T9>
    operator ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
        T9> >() const {
      return ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> >(
          new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
          static_cast<ParamGenerator<T1> >(g1_),
          static_cast<ParamGenerator<T2> >(g2_),
          static_cast<ParamGenerator<T3> >(g3_),
          static_cast<ParamGenerator<T4> >(g4_),
          static_cast<ParamGenerator<T5> >(g5_),
          static_cast<ParamGenerator<T6> >(g6_),
          static_cast<ParamGenerator<T7> >(g7_),
          static_cast<ParamGenerator<T8> >(g8_),
          static_cast<ParamGenerator<T9> >(g9_)));
    }
  
   private:
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductHolder9& other);
  
    const Generator1 g1_;
    const Generator2 g2_;
    const Generator3 g3_;
    const Generator4 g4_;
    const Generator5 g5_;
    const Generator6 g6_;
    const Generator7 g7_;
    const Generator8 g8_;
    const Generator9 g9_;
  };  // class CartesianProductHolder9
  
  template <class Generator1, class Generator2, class Generator3,
      class Generator4, class Generator5, class Generator6, class Generator7,
      class Generator8, class Generator9, class Generator10>
  class CartesianProductHolder10 {
   public:
  CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
      const Generator3& g3, const Generator4& g4, const Generator5& g5,
      const Generator6& g6, const Generator7& g7, const Generator8& g8,
      const Generator9& g9, const Generator10& g10)
        : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
            g9_(g9), g10_(g10) {}
    template <typename T1, typename T2, typename T3, typename T4, typename T5,
        typename T6, typename T7, typename T8, typename T9, typename T10>
    operator ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9,
        T10> >() const {
      return ParamGenerator< ::std::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9,
          T10> >(
          new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
              T10>(
          static_cast<ParamGenerator<T1> >(g1_),
          static_cast<ParamGenerator<T2> >(g2_),
          static_cast<ParamGenerator<T3> >(g3_),
          static_cast<ParamGenerator<T4> >(g4_),
          static_cast<ParamGenerator<T5> >(g5_),
          static_cast<ParamGenerator<T6> >(g6_),
          static_cast<ParamGenerator<T7> >(g7_),
          static_cast<ParamGenerator<T8> >(g8_),
          static_cast<ParamGenerator<T9> >(g9_),
          static_cast<ParamGenerator<T10> >(g10_)));
    }
  
   private:
    // No implementation - assignment is unsupported.
    void operator=(const CartesianProductHolder10& other);
  
    const Generator1 g1_;
    const Generator2 g2_;
    const Generator3 g3_;
    const Generator4 g4_;
    const Generator5 g5_;
    const Generator6 g6_;
    const Generator7 g7_;
    const Generator8 g8_;
    const Generator9 g9_;
    const Generator10 g10_;
  };  // class CartesianProductHolder10
  
  }  // namespace internal
  }  // namespace testing
  
  #endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
  