Por que static_cast é necessário na implementação de is_nothrow_constructible do gcc?

11

Retirado da implementação do GCC de type_traitspor que é static_castnecessário aqui?

template <typename _Tp, typename... _Args>
struct __is_nt_constructible_impl
    : public integral_constant<bool, noexcept(_Tp(declval<_Args>()...))> {};

template <typename _Tp, typename _Arg>
struct __is_nt_constructible_impl<_Tp, _Arg>
    : public integral_constant<bool,
                               // Why is `static_cast` needed here?
                               noexcept(static_cast<_Tp>(declval<_Arg>()))> {};
João Pires
fonte
Essa inconsistência parece estranha
Lightness Races in Orbit em
4
Você deve fazer perguntas como esta na lista de discussão libstdc ++ relevante
Lightness Races in Orbit

Respostas:

12

Um tipo não pode ser construído de uma lista de argumentos se a declaração da variável inventada

T t(declval<Args>()...);

seria bem formado e é conhecido por não lançar exceções . No caso do argumento plural, isso é equivalente (módulo noexcept destrutibilidade, consulte LWG 2116 ) à boa formação e notowow da expressão de conversão de tipo

T(declval<Args>()...)

No entanto, no caso de argumento único, a expressão T(declval<Args>())é tratada como uma expressão de conversão , que pode chamar const_castereinterpret_cast ; o uso explícito de static_castrestaura a equivalência ao formulário de declaração.

Como um exemplo concreto , considere os tipos:

struct D;
struct B { operator D&&() const; };
struct D : B {};

Aqui um static_castde B constpara D&&deve usar o operador de conversão, mas uma expressão de conversão pode ignorar o operador de conversão e, portanto, não é exceção. Portanto, omitir o static_castdaria o resultado errado para is_nothrow_constructible<D&&, B const>.

ecatmur
fonte
Portanto, o static_casté necessário para que a expressão seja sempre tratada como em direct initializationvez de como cast expression?
João Pires
11
@ JoãoPires sim, está certo. Ainda não é exatamente o que o padrão exige, porque não é possível testar, exceto uma declaração usando o noexceptoperador, mas é muito mais próximo.
ecatmur 7/01
Obrigado pela ajuda! : D
João Pires