title: C++ template code works in msvc 2015 but not 2017
body: <p>I have a template metafunction that extends std::make_signed to be able to handle tuple types, that is applying std::make_signed to each component type of a tuple. It uses boost::mpl for much of the work.</p>
  
  <p>It works as expected when compiling with vc2015 but not when switched to 2017 (I use vs2017 and have flipped the platform tool set configuration in the project settings with no other change and witness this behavior). The errors are buryed in boost mpl, and I am not sure if this is a bug in my code, something wrong in boost::mpl or something wrong with msvc2017.</p>
  
  <p>I would greatly appreciate help tracking down what is going on here.</p>
  
  <p>The following sample is my complete test project, even to the point of disabling PCH.</p>
  
  <pre><code>#include &lt;cstdint&gt;
  #include &lt;tuple&gt;
  #include &lt;type_traits&gt;
  
  #include &lt;boost/mpl/vector.hpp&gt;
  #include &lt;boost/mpl/transform.hpp&gt;
  #include &lt;boost/mpl/equal_to.hpp&gt;
  #include &lt;boost/mpl/distance.hpp&gt;
  #include &lt;boost/mpl/int.hpp&gt;
  #include &lt;boost/mpl/deref.hpp&gt;
  #include &lt;boost/mpl/reverse.hpp&gt;
  
  //
  // hcc_meta::to_variadic is a metafunction that takes a boost::mpl sequence and produces a variadic template argument pack.
  // It is based on code from http://bx12.blogspot.com/2010/04/converting-mpl-sequence-to-variadic.html
  // One improvement that has been made is that the template type to pass the expanded argument pack to is now taken as a template template parameter rather than being hard-coded.
  namespace hcc_meta
  {
      namespace impl
      {
          template&lt;typename F, typename L&gt;
          struct exit_ : boost::mpl::equal_to&lt;typename boost::mpl::distance&lt;F, L&gt;::type, typename boost::mpl::int_&lt;0&gt;&gt;
          {
          };
  
          template&lt;typename F, typename L, bool exit, template &lt;typename ...&gt; class TargType, typename ... Args&gt;
          struct to_variadic
          {
              typedef typename boost::mpl::deref&lt;F&gt;::type front_;
              typedef typename boost::mpl::next&lt;F&gt;::type next_;
              typedef typename impl::exit_&lt;next_, L&gt;::type exit_;
              typedef typename to_variadic&lt;next_, L, exit_::value, TargType, front_, Args...&gt;::type type;
          };
  
          template&lt;typename F, typename L, template&lt;typename ...&gt; class TargType, typename ... Args&gt;
          struct to_variadic&lt;F, L, true, TargType, Args...&gt;
          {
              typedef TargType&lt;Args...&gt; type;
          };
  
          template&lt;typename Seq&gt;
          struct seq_traits
          {
              typedef typename boost::mpl::begin&lt;Seq&gt;::type first_;
              typedef typename boost::mpl::end&lt;Seq&gt;::type last_;
              typedef typename impl::exit_&lt;first_, last_&gt;::type exit_;
          };
      }//impl
  
      template&lt;typename Seq, template &lt;typename ...&gt; class TargType&gt;
      struct to_variadic
      {
          typedef typename boost::mpl::reverse&lt;Seq&gt;::type reversed_;
          typedef typename impl::to_variadic&lt;typename impl::seq_traits&lt;reversed_&gt;::first_, typename impl::seq_traits&lt;reversed_&gt;::last_, impl::seq_traits&lt;Seq&gt;::exit_::value, TargType&gt;::type type;
      };
  }
  
      // Defines a static member 'value' that is 'true' if 'Ty' is a specialization of std;::tuple.
      template&lt;typename Ty&gt;
      struct is_std_tuple
      {
          static bool const value = false;
      };
      template&lt;typename ... Types&gt;
      struct is_std_tuple&lt;std::tuple&lt;Types...&gt;&gt;
      {
          static bool const value = true;
      };
  
      //
          // Helper that only applies std::make_signed to types that can take it.
          // For all other types 'type' is an alias for 'Ty'.
      template&lt;typename Ty&gt;
      struct make_signed_if_possible
      {
  #pragma warning(push)
  #pragma warning(disable : 4348) // 'make_signed_if_possible&lt;U1&gt;::apply': redefinition of default parameter: parameter 2 
          // Use a nested template to hide the use of the default template argument from users of make_signed_if_possible.
          template&lt;typename Ty, bool = std::is_integral&lt;Ty&gt;::value || std::is_enum&lt;Ty&gt;::value || is_std_tuple&lt;Ty&gt;::value&gt;
          struct apply;
  #pragma warning(pop)
          template&lt;typename Ty&gt;
          struct apply&lt;Ty, true&gt;
          {
              typedef typename std::make_signed&lt;Ty&gt;::type type;
          };
          template&lt;typename Ty&gt;
          struct apply&lt;Ty, false&gt;
          {
              typedef Ty type;
          };
          typedef typename apply&lt;Ty&gt;::type type;
      };
  
      // Define the std::make_signed metafunction for tuples.
      // The type member is a tuple with the same number of members as the input but with each element that makes a signedness distinction transformed to the signed variant.
      template&lt;typename ... Types&gt;
      struct std::make_signed&lt;std::tuple&lt;Types...&gt;&gt;
      {
          typedef boost::mpl::vector&lt;Types...&gt; seq;
          typedef typename boost::mpl::transform&lt;seq, typename make_signed_if_possible&lt;boost::mpl::_1&gt;&gt;::type transformed;
          typedef typename hcc_meta::to_variadic&lt;transformed, std::tuple&gt;::type type;
      };
  
      int main()
      {
          typedef std::tuple&lt;std::uint64_t, std::uint64_t&gt; utypes;
          using stypes = typename std::make_signed&lt;utypes&gt;::type;
          return 0;
      }
  </code></pre>
  
  <p>I get the following errors when building with vc2017. For reference, the first line of my own code - line 101 of testbed.cpp - is "typedef typename boost::mpl::transform>::type transformed;":</p>
  
  <pre><code>1&gt;d:\devtools\boost_1_66_0\boost\mpl\clear.hpp(30): error C2903: 'apply': symbol is neither a class template nor a function template
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): note: see reference to class template instantiation 'boost::mpl::clear&lt;P1&gt;' being compiled
  1&gt;        with
  1&gt;        [
  1&gt;            P1=make_signed_if_possible&lt;boost::mpl::_1&gt;
  1&gt;        ]
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\eval_if.hpp(41): note: see reference to class template instantiation 'boost::mpl::transform1&lt;Seq1,Seq2OrOperation,OperationOrInserter&gt;' being compiled
  1&gt;        with
  1&gt;        [
  1&gt;            Seq1=make_signed_if_possible&lt;boost::mpl::_1&gt;,
  1&gt;            Seq2OrOperation=boost::mpl::na,
  1&gt;            OperationOrInserter=boost::mpl::na
  1&gt;        ]
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(138): note: see reference to class template instantiation 'boost::mpl::eval_if&lt;boost::mpl::or_&lt;boost::mpl::is_na&lt;boost::mpl::na&gt;,boost::mpl::is_lambda_expression&lt;Seq2OrOperation&gt;,boost::mpl::not_&lt;boost::mpl::is_sequence&lt;boost::mpl::na&gt;&gt;,boost::mpl::false_,boost::mpl::false_&gt;,boost::mpl::transform1&lt;Seq1,Seq2OrOperation,OperationOrInserter&gt;,boost::mpl::transform2&lt;Seq1,Seq2OrOperation,OperationOrInserter,Inserter&gt;&gt;' being compiled
  1&gt;        with
  1&gt;        [
  1&gt;            Seq2OrOperation=boost::mpl::na,
  1&gt;            Seq1=make_signed_if_possible&lt;boost::mpl::_1&gt;,
  1&gt;            OperationOrInserter=boost::mpl::na,
  1&gt;            Inserter=boost::mpl::na
  1&gt;        ]
  1&gt;z:\projects\testbed\testbed\testbed.cpp(101): note: see reference to class template instantiation 'boost::mpl::transform&lt;make_signed_if_possible&lt;boost::mpl::_1&gt;,boost::mpl::na,boost::mpl::na,boost::mpl::na&gt;' being compiled
  1&gt;z:\projects\testbed\testbed\testbed.cpp(108): note: see reference to class template instantiation 'std::make_signed&lt;utypes&gt;' being compiled
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\clear.hpp(30): error C3770: 'unknown-type': is not a valid base class
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): error C2039: 'type': is not a member of 'boost::mpl::clear&lt;P1&gt;'
  1&gt;        with
  1&gt;        [
  1&gt;            P1=make_signed_if_possible&lt;boost::mpl::_1&gt;
  1&gt;        ]
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): note: see declaration of 'boost::mpl::clear&lt;P1&gt;'
  1&gt;        with
  1&gt;        [
  1&gt;            P1=make_signed_if_possible&lt;boost::mpl::_1&gt;
  1&gt;        ]
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): error C2146: syntax error: missing '&gt;' before identifier 'type'
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): error C2146: syntax error: missing '&gt;' before identifier 'type'
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): error C2146: syntax error: missing '&gt;' before identifier 'type'
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\push_back.hpp(42): error C2903: 'apply': symbol is neither a class template nor a function template
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\if.hpp(63): note: see reference to class template instantiation 'boost::mpl::has_push_back&lt;int&gt;' being compiled
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): note: see reference to class template instantiation 'boost::mpl::if_&lt;boost::mpl::has_push_back&lt;int&gt;,boost::mpl::aux::transform1_impl&lt;P1,P2,boost::mpl::back_inserter&lt;int&gt;&gt;,boost::mpl::aux::reverse_transform1_impl&lt;P1,P2,boost::mpl::front_inserter&lt;int&gt;&gt;&gt;' being compiled
  1&gt;        with
  1&gt;        [
  1&gt;            P1=make_signed_if_possible&lt;boost::mpl::_1&gt;,
  1&gt;            P2=boost::mpl::na
  1&gt;        ]
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\push_back.hpp(42): error C3770: 'unknown-type': is not a valid base class
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\if.hpp(63): error C2039: 'value': is not a member of 'boost::mpl::has_push_back&lt;int&gt;'
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): note: see declaration of 'boost::mpl::has_push_back&lt;int&gt;'
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\if.hpp(63): error C2065: 'value': undeclared identifier
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\if.hpp(67): error C2975: 'C': invalid template argument for 'boost::mpl::if_c', expected compile-time constant expression
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\if.hpp(30): note: see declaration of 'C'
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\copy.hpp(54): error C2039: 'type': is not a member of 'boost::mpl::clear&lt;P1&gt;'
  1&gt;        with
  1&gt;        [
  1&gt;            P1=int
  1&gt;        ]
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\copy.hpp(54): note: see declaration of 'boost::mpl::clear&lt;P1&gt;'
  1&gt;        with
  1&gt;        [
  1&gt;            P1=int
  1&gt;        ]
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\copy.hpp(54): error C2146: syntax error: missing '&gt;' before identifier 'type'
  1&gt;d:\devtools\boost_1_66_0\boost\mpl\copy.hpp(54): error C2146: syntax error: missing '&gt;' before identifier 'type'
  </code></pre>