Eu fiz uma macro para o operador "implies". Funciona bem em geral, mas quebra no Clang quando usado em um conceito ou uma cláusula require.
namespace detail
{
template <typename T>
concept BoolLike = requires(T &&t) {(T &&)t ? true : false;};
struct Implies
{
template <BoolLike T>
friend constexpr bool operator||(T &&lhs, Implies)
{
return !bool((T &&)lhs);
}
};
}
#define IMPLIES ||::detail::Implies{}||
template <typename T>
concept A = true IMPLIES true;
static_assert(A<int>);
Clang diz:
<source>:19:18: error: atomic constraint must be of type 'bool' (found '::detail::Implies')
19 | concept A = true IMPLIES true;
| ^~~~~~~
<source>:16:19: note: expanded from macro 'IMPLIES'
16 | #define IMPLIES ||::detail::Implies{}||
| ^~~~~~~~~~~~~~~~~~~
Enquanto GCC e MSVC aceitam alegremente esse código. Qual compilador está correto?
Operadores lógicos sobrecarregados não funcionam realmente em expressões de restrição (no nível superior): o mecanismo de normalização de restrição transforma expressões das formas
E1 || E2
eE1 && E2
em disjunções e conjunções, respectivamente, com base puramente em sua forma sintática, sem levar em consideração se há uma sobrecarga fornecida pelo usuário para o operador ( [temp.constr.normal] ).Neste exemplo específico, isso significa que a forma normal da
A
expressão de restrição de contém, entre outras coisas, uma restrição atômica formada a partir da expressão::detail::Implies{}
, que nunca é do tipobool
.[temp.constr.atomic]/3 :
Como este programa nunca verifica a restrição atômica inválida para satisfação (por causa de
||
curto-circuitos), ele é malformado e não requer diagnóstico ( [temp.res.general]/6.4 ):