if constexpr 和 C4702(以及 C4100 和 C4715)

if constexpr and C4702 (and C4100, and C4715)

有没有办法解决以下问题:

此代码产生 C4702 警告 'unreachable code'(在 VC++ 15.8 和 /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
}

抑制C4100 'unreferenced formal parameter'警告,我已经在使用技巧了

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

添加的简单思路

    else
    {
        return false;
    }

导致警告 C4715 'not all control paths return a value'。

它是不可访问的,因为对于基于模板参数的模板的给定扩展,该函数将通过条件并且return真 失败并且 return 错误。对于同一类型,不可能有任何一种情况。它基本上扩展到

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

我将其重写为只有一个 return 语句。

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;
}

此外,在条件为真的情况下,变体 not 未使用。您可能希望将抑制警告(基本上变成 (void)variant)的那行移动到 else 语句。

作为对直接问题的直接回答。关于 if constexpr 的主题。考虑一下:

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;
 }
}

根据if constexpr表达式的布尔结果,编译器实际上产生了两个函数。此版本在 if constexpr() 产生 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;
}

此版本是在 if constexpr() 产生错误时生成的:

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

第二个版本可能会发出关于未使用参数的警告。但是(似乎)如果使用 clang/gcc/msvc 的最新版本则不会。对于较旧的编译器,"old123987" 也指出可以将标准属性添加到签名中。像这样:

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

这将停止发出警告。