Ao navegar pela implementação atual do gcc de novos cabeçalhos C ++ 11, me deparei com o token "......". Você pode verificar se o código a seguir é compilado corretamente [via ideone.com].
template <typename T>
struct X
{ /* ... */ };
template <typename T, typename ... U>
struct X<T(U......)> // this line is the important one
{ /* ... */ };
Então, qual é o significado deste token?
editar: Parece que TÃO aparado "......" no título da pergunta para "...", eu realmente quis dizer "......". :)
c++
c++11
variadic-templates
Vitus
fonte
fonte
...
seguido por...
.U...
seguido por...
. Mesmo assim, muito estranho.<functional>
e<type_traits>
, sempre no contexto de uma lista de argumentos de função dentro de um parâmetro de modelo.Respostas:
Cada instância dessa estranheza é emparelhada com um caso de uma única elipse regular.
Meu palpite é que a elipse dupla é semelhante em significado a
_ArgTypes..., ...
, ou seja, uma expansão de modelo variadic seguida por uma lista de varargs de estilo C.Aqui está um teste que apóia essa teoria ... Acho que temos um novo vencedor para o pior pseudo-operador de todos os tempos.
Edit: Isso parece estar em conformidade. §8.3.5 / 3 descreve uma maneira de formar a lista de parâmetros como
Assim, a elipse dupla é formada por uma lista de declaração de parâmetros terminando com um pacote de parâmetros, seguido por outras reticências.
A vírgula é puramente opcional; §8.3.5 / 4 diz
Isso está dentro de um declarador abstrato, [editar] mas Johannes afirma que eles estão se referindo a um declarador abstrato dentro de uma declaração de parâmetro. Eu me pergunto por que eles não disseram "parte de uma declaração de parâmetro" e por que essa frase não é apenas uma nota informativa ...
Além disso,
va_begin()
in<cstdarg>
requer um parâmetro antes da lista de varargs, de modo que o protótipof(...)
especificamente permitido por C ++ é inútil. A referência cruzada com C99 é ilegal na planície C. Então, isso é muito bizarro.Nota de uso
A pedido, aqui está uma demonstração da elipse dupla:
fonte
std::is_function
'svalue
deve ser verdadeiro mesmo que a função seja C varargs um e porque T (U ...) não é compatível com tal função, você precisa dessa loucura. Por exemplo, int f (int, char, ...) corresponde a T (U ......) exatamente com T = int, U = {int, char} e o token varargs "...".void (int...)
, aqui, o...
não faz parte do declarador abstratoint
, portanto, é sinônimo devoid(int, ...)
. Se você escrevervoid(T...)
eT
for um pacote de parâmetros de modelo,...
será parte do declarador abstrato e, portanto, não seria equivalente avoid(T, ...)
.f(...)
é usado fortemente como uma sobrecarga de função de fallback na metaprogramação de template, onde esta informação não é necessária (e onde a função nem mesmo é chamada).no vs2015, separar vírgulas é essencial na versão do modelo:
um exemplo de instanciação é:
Atenciosamente, FM.
fonte