Если 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
,