Если constexpr и C4702 (и C4100, и C4715)

Есть ли способ исправить следующую проблему:

Этот код выдает предупреждение C4702 "недоступный код" (на 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 "не имеющий ссылки формальный параметр", я уже использую трюк

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

Простая идея добавления

    else
    {
        return false;
    }

приводит к предупреждению C4715 "не все пути управления возвращают значение".

3 ответа

Решение

Это недоступно, потому что для данного расширения шаблона, основанного на аргументах шаблона, функция будет только когда-либо проходить условие и возвращать true или сбой и возвращать false. Нет ни одного случая, когда это могло бы пойти так или иначе для одного и того же типа. Это по существу расширяется до

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

Я бы переписал его, чтобы было только одно возвращаемое выражение.

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

Также в том случае, когда условие истинно, вариант не используется. Возможно, вы захотите переместить эту строку, которая подавляет предупреждение (которое в основном превращается в (void) вариант), в оператор 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;
 }
}

В зависимости от результата bool if constexpr выражение, компилятор на самом деле производит две функции. Эта версия производится, когда if constexpr() дает истину:

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

Это остановит предупреждение.

Не совсем понятно, чего вы пытаетесь достичь, но, возможно, вы можете использовать следующий код для решения вашей непосредственной проблемы:

template <typename T, typename ... params >
inline bool 
     match_monostate
// note: this signature ensures only variants can be passed
      (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;
    }
}

Возможное использование:

    // what is supposed to happen?
    std::variant<std::monostate, int, float> vmif{ std::monostate() };
    // this will compile
        auto rez2 = match_monostate<std::monostate>(vmif);

    std::variant<int,float> vif{} ;
    // this will not compile
    // auto rez3 = match_monostate<std::monostate>(vmif);

Также. Правильный стандартный способ C++ для предупреждения о неиспользуемых аргументах или переменных - использовать атрибут: [[maybe_unused]]... определенно не void() "Трюк".

Для поклонников макросов, которые также думают, что стандартный C++ почему-то не является стандартным, правильно названный и реализованный макрос может быть следующим:

// for variables and expressions
// guranteed no evaluation
// guaranteed zero bytes overhead
// standard c++ 
// works in any space
#define DBJ_UNUSED(x) static_assert( (noexcept(x),true) )
#endif

Также. внутри match_monostate()Как показано выше, кажется, что не нужно подавлять предупреждения о неиспользуемых аргументах / переменных.

Обновление: это верно для MSVC, только если уровень предупреждения не выше /W3,

Онлайн доказательство концепции здесь

Другие вопросы по тегам