if constexpr and C4702 (and C4100, and C4715)

Viewed 510

Is there a way to fix the following problem:

This code produces a C4702 warning 'unreachable code' (on VC++ 15.8 with /std:c++17)

template <typename T, typename VariantType>
inline bool MatchMonostate( VariantType& variant )
{
    SUPPRESS_C4100( variant );
    if constexpr ( std::is_same_v<T, std::monostate> )
    {
        variant = std::monostate();
        return true;
    }
    return false;  // !!! unreachable if the above is true !!! => C4702
}

to suppress the C4100 'unreferenced formal parameter' warning, I'm already using the trick

#define SUPPRESS_C4100(x) ((void)x)

The simple idea of adding

    else
    {
        return false;
    }

results in warning C4715 'not all control paths return a value' instead.

2 Answers

It's unreachable because for a given expansion of the template based on the template arguments the function will only ever pass the condition and return true or fail and return false. There is no case where it could go either way for the same type. It's essentially expanding to

if (true) {
  return true;
}
return false; // Obviously will never happen

I'd rewrite it to only have a single return statement.

template <typename T, typename VariantType>
inline bool MatchMonostate( VariantType& variant )
{
    SUPPRESS_C4100( variant );
    bool retval = false;
    if constexpr ( std::is_same_v<T, std::monostate> )
    {
        variant = std::monostate();
        retval = true;
    }
    return retval;
}

Also, in the case where the condition is true variant is not unused. You may want to move that line that suppresses the warning (which basically turns into (void)variant) to an else statement.

As the direct answer to the direct question. On the subject of if constexpr. Consider this:

template <typename T, typename ... params >
 inline bool match_monostate
  (std::variant<params ...> & variant) noexcept    
{
 if constexpr (std::is_same_v<T, std::monostate>)
 {
     variant = std::monostate{} ;
 //  compiles only if called with variant
 //  whose one alternative is std::monostate
     return true;
 }
 else {
    return false;
 }
}

Depending on the bool result of the if constexpr expression, compiler actually produces two functions. This version is produced when if constexpr() yields true:

  template <typename T, typename ... params >
 inline bool 
 match_monostate  (std::variant<params ...> & variant)  noexcept
{
    variant = std::monostate{} ;
//  compiles only if called with variant
//  whose one alternative is std::monostate
    return true;
}

This version is produced when if constexpr() yields false:

template <typename T, typename ... params >
 inline bool 
 match_monostate  (std::variant<params ...> & variant)  noexcept
{
    return false;
}

The second version might emit warnings about unused argument. But (it seems) not if using the latest versions of clang/gcc/msvc. For older compilers as "old123987" also pointed out one can add the standard attribute to the signature. Like so:

 template <typename T, typename ... params >
 inline bool 
 match_monostate  ([[maybe_unused]] std::variant<params ...> & variant) ;

That will stop the warning emitting.

Related