Tenho um código que simplifiquei para isto:
#include <iostream>
#include <string>
enum En
{
one,
two,
three
};
auto get_str(int n, En en)
{
if (n > 0)
{
return std::to_string(n);
}
switch (en)
{
case one:
return std::string("one");
case two:
return std::string("two");
case three:
return std::string("three");
}
}
int main()
{
auto str = get_str(3, two);
std::cout << str << '\n';
}
Veja no explorador do compilador .
Quando compilo com GCC 14.2 ou 13.3.0 (com ou sem -Wall -Wextra
), ele reclama da get_str
função:
warning: control reaches end of non-void function [-Wreturn-type]
.
O Clang 15.0 e superior -Wall -Wextra
não emite nenhum aviso. O VS17.10 também reclama: warning C4715: 'get_str': not all control paths return a value
.
O que faz com que Clang discorde? Qual é o caminho que ignora return
s?
Todos os compiladores estão corretos à sua maneira. A redação relevante está em [dcl.enum] p8 :
O que isso significa para seu código é:
En
, ele pode ter o valorEn(3)
, que não é nenhum dos enumeradoresone
two
, ethree
. Isso ocorre porque o inteiro de largura mínima que pode armazenarthree
tem dois bits, então0
,1
,2
, e3
podem ser representados. Além disso, o padrão diz explicitamente que ter tais "valores sem enumeradores" é possível.four
, ainda pode haver mais valores porque o padrão só exige uma largura mínima para aquele "inteiro hipotético".Quando o GCC avisa, está correto. Se
En(3)
for passado paraget_str
, o controle flui para fora do final da função, e você obtém um comportamento indefinido.Quando outros compiladores não avisam você, eles também estão corretos. O padrão não exige que um aviso seja emitido nessa situação.
Há algumas soluções alternativas possíveis aqui, que devem silenciar o aviso:
std::unreachable()
ao final da função.default:
caso e retornar ou ligarstd::unreachable()
para lá.