std::variant template deduction when isolating containing type

I have been making a serializer today and am having trouble getting it to work with variants.

I have used this process before for various other things where I keep trimming off the type till I get to the one type I need. However, it seems VC++ can't deduce it this time.

Here is a complete example of the error.

 #include <type_traits>
 #include <variant>
 #include <iostream>
 #include <sstream>

 void serialize( auto& s, float v ) {
     std::cout << "serialize float";
 }
 void serialize( auto& s, int v ) {
     std::cout << "serialize int";
 }
 void serialize( auto& s, bool v ) {
     std::cout << "serialize bool";
 }
 namespace detail
 {
     template<typename VariantT, typename T1, typename ...Rest>
     void serialize_variant( auto& s, const VariantT& v ) {
         if ( std::holds_alternative<T1>( v ) )
             return serialize( s, std::get<T1>( v ) );
         else if ( sizeof...(Rest) >= 1 )
             return serialize_variant<VariantT, Rest...>( s, v );
         else return;
     }
 }
 template<typename ...VariantTs>
 void serialize( auto& s, const std::variant<VariantTs...>& v ) {
      detail::serialize_variant<std::variant<VariantTs...>, VariantTs...>( s, v );
 }
 int main() {
     std::stringstream s{};
     std::variant<float, int, bool> x = true;
     serialize( s, x );
 }

I am confused why this is not working. It should check to see if it T1 is the type the variant contains. If it is not then it checks if there are more types to check and calls the same serialize_variant function with one less type when there is, otherwise it just returns. It is throwing a no matching overload for serialize_variant on the recursive call and it says it cannot deduce T1.

Can anyone shed some light on why this is failing to compile?

It is the following errors I am getting

Error   C2672   'serialize_variant': no matching overloaded function found   
Error   C2783   'void detail::serialize_variant(_T0 &,const VariantT &)': could not deduce 
    template argument for 'T1'   

Thanks.


The branch with sizeof...(Rest) >= 1 must also be valid when the condition is false, but it isn't. You can get it discarded when the condition is false via if constexpr. Moreoever you were trying to return something but the return type is void.

 namespace detail
 {
     template<typename VariantT, typename T1, typename ...Rest>
     void serialize_variant( auto& s, const VariantT& v ) {
         if ( std::holds_alternative<T1>( v ) )
             /*return*/ serialize( s, std::get<T1>( v ) );
         else { 
            if constexpr ( sizeof...(Rest) >= 1 )
             /*return*/ serialize_variant<VariantT, Rest...>( s, v );
            else return;
         }
     }
 }

Complete example