Não tenho certeza se o título da minha pergunta é o mais apropriado e terei prazer em alterá-lo para algo mais claro se receber sugestões adequadas.
Em um vídeo em C++ cujo assunto não é esse aqui, vi esta definição:
#include <vector>
// before ":" V is forward declared, it's enough for std::vector?
// node in a tree
struct V : std::vector<V> {};
(os comentários são de minha autoria).
Meu entendimento é que é possível ter essa declaração aparentemente circular, pois no base-clause
local, struct V
já está (forward) declarado.
Mas é C++ legal, pois não acho que a declaração de classe seja explícita sobre isso.
forward declaration
é definido por si mesmo ( struct V;
, então você pode declarar a std::vector<V>)
, mas não na sintaxe completa da declaração de classe.
O texto na classe derivada :
Qualquer tipo de classe ( seja declarado com class-key class ou struct ) pode ser declarado como derivado...
(negrito meu) parece implicar que class-key class
ou class-key struct
(sem terminar ;
) já são declarações completas. É verdade, está mais explícito na norma?
Se sim, isso pode me dar oportunidades para designs interessantes, então gostaria de ter certeza de que é legal.
[EDIT] um exemplo mais explícito, semstd::vector
template <typename T>
struct refwrapper {
T* wrapped;
virtual ~refwrapper() = default;
};
template <typename T>
struct plainwrapper {
T wrapped;
virtual ~plainwrapper() = default;
};
// OK? R is declared at the base-clause
struct R : refwrapper<R> {};
// KO P is incomplete at the base-clause
// struct P: plainwrapper<P>
// {};
O nome da classe fica visível para pesquisa imediatamente após o identificador. Consulte [basic.scope.pdecl]/3 .
Porém, como sempre, até o fechamento
}
da definição da classe a classe fica incompleta. O especificador de classe base não é uma exceção, como são alguns dos chamados contextos de classe completos .Usar um tipo como classe base requer que ele seja completo. Portanto
std::vector<V>
será instanciado pelo uso como especificador de classe base, ondeV
ainda está incompleto.Geralmente instanciar um modelo de biblioteca padrão com um tipo incompleto como argumento de modelo causa um comportamento indefinido.
No entanto, como C++ 17
std::vector
é uma das exceções: é permitido instanciarstd::vector
um tipo incompleto como argumento de modelo, desde que o tipo seja concluído antes de qualquer função membro dastd::vector
especialização ser referenciada.Então sim,
struct V : std::vector<V> {};
é válido desde C++ 17, pois não faz referência a nenhum membrostd::vector<V>
antes do fechamento}
.