O código a seguir não compila.
int a = 1, b = 2, c = 3;
int& arr[] = {a,b,c,8};
O que o padrão C ++ diz sobre isso?
Eu sei que posso declarar uma classe que contém uma referência e criar uma matriz dessa classe, como mostrado abaixo. Mas eu realmente quero saber por que o código acima não é compilado.
struct cintref
{
cintref(const int & ref) : ref(ref) {}
operator const int &() { return ref; }
private:
const int & ref;
void operator=(const cintref &);
};
int main()
{
int a=1,b=2,c=3;
//typedef const int & cintref;
cintref arr[] = {a,b,c,8};
}
É possível usar em struct cintref
vez de const int &
simular uma matriz de referências.
intlink value = 8;
funciona. verifique se você não acredita.operator=
. As referências não podem ser recolocadas. Se você realmente quer tal semântica - embora eu não tenho, pessoalmente, encontrou uma situação em que eles são praticamente útil - entãostd::reference_wrapper
seria a maneira de fazê-lo, uma vez que, na verdade, armazena um ponteiro, mas fornece a referência semelhantesoperator
s e não permitir recolocar. Mas então eu usaria um ponteiro!Respostas:
Respondendo à sua pergunta sobre o padrão, posso citar o Padrão C ++ §8.3.2 / 4 :
fonte
struct
cujo único membro seja uma referência. Mas então, ao fazer isso, você agora tem uma referência e um objeto pai para nomear ... o que agora significa que você pode declarar sem ambiguidade qual endereço deseja. Parece óbvio ... então por que ninguém disse isso?What more is there to say?
Uma justificativa para o porquê ? Sou a favor do Padrão, mas apenas citá-lo e supor que esse é o fim da discussão parece uma maneira infalível de destruir o pensamento crítico dos usuários - junto com qualquer potencial para a linguagem evoluir, por exemplo, além das limitações de omissão ou restrição artificial. Há muito 'porque o Padrão diz' aqui - e não o suficiente 'e é muito sensato dizer isso, devido às seguintes razões práticas'. Não sei por que os votos positivos fluem tão ansiosamente para respostas que dizem apenas o primeiro sem sequer tentar explorá-lo.Referências não são objetos. Eles não têm armazenamento próprio, apenas referenciam objetos existentes. Por esse motivo, não faz sentido ter matrizes de referências.
Se você deseja um objeto leve que faça referência a outro objeto, use um ponteiro. Você só poderá usar a
struct
com um membro de referência como objetos em matrizes se fornecer inicialização explícita para todos os membros de referência para todas asstruct
instâncias. As referências não podem ser inicializadas por padrão.Edit: Como jia3ep observa, na seção padrão sobre declarações, há uma proibição explícita de matrizes de referências.
fonte
Esta é uma discussão interessante. Claramente, matrizes de árbitros são totalmente ilegais, mas IMHO a razão pela qual não é tão simples como dizer 'eles não são objetos' ou 'eles não têm tamanho'. Eu apontaria que as próprias matrizes não são objetos completos no C / C ++ - se você se opuser a isso, tente instanciar algumas classes de modelo stl usando uma matriz como parâmetro de modelo de 'classe' e veja o que acontece. Você não pode devolvê-los, atribuí-los, passá-los como parâmetros. (um parâmetro de matriz é tratado como um ponteiro). Mas é legal fazer matrizes de matrizes. As referências têm um tamanho que o compilador pode e deve calcular - você não pode sizeof () uma referência, mas pode criar uma estrutura contendo nada além de referências. Ele terá um tamanho suficiente para conter todos os ponteiros que implementam as referências. Você pode'
Na verdade, você pode adicionar esta linha à definição de estrutura
... e agora eu tenho algo que se parece muito com uma variedade de referências:
Agora, isso não é uma matriz real, é uma sobrecarga de operador; ele não fará coisas que as matrizes normalmente fazem como sizeof (arr) / sizeof (arr [0]), por exemplo. Mas faz exatamente o que eu quero que uma matriz de referências faça, com C ++ perfeitamente legal. Exceto (a) é difícil configurar mais de 3 ou 4 elementos e (b) está fazendo um cálculo usando um monte de?: O que pode ser feito usando a indexação (não com a indexação normal de C-ponteiro-cálculo-semântica) , mas indexando). Eu gostaria de ver um tipo muito limitado de 'matriz de referência' que realmente pode fazer isso. Ou seja, uma matriz de referências não seria tratada como uma matriz geral de coisas que são referências, mas seria uma nova 'matriz de referência' fazer com modelos).
isso provavelmente funcionaria, se você não se importar com esse tipo de desagradável: reformule '* this' como uma matriz de int * 's e retorne uma referência feita a partir de uma: (não recomendado, mas mostra como a' matriz 'adequada trabalharia):
fonte
std::tuple<int&,int&,int&> abcref = std::tie( a,b,c)
- que cria uma "matriz" de referências que só podem ser indexadas por constantes em tempo de compilação usando std :: get. Mas você não pode fazerstd::array<int&,3> abcrefarr = std::tie( a,b,c)
. Talvez haja uma maneira de fazer isso que eu não conheça. Parece-me que deve haver uma maneira de escrever uma especializaçãostd::array<T&,N>
que possa fazer isso - e, portanto, uma funçãostd::tiearray(...)
que retorne uma dessas (ou permitastd::array<T&,N>
aceitar inicializador contendo endereços = {& v1, & v2 etc})?:
std::array<T,N>
, facilmente definido no código do aplicativo, não foi adicionado ao std :: até o c ++ 11, provavelmente porque é difícil ter isso sem nenhuma maneira de do= {1,2,3};
Isso foi 'hacking de linguagem'?Comentário à sua edição:
Melhor solução é
std::reference_wrapper
.Detalhes: http://www.cplusplus.com/reference/functional/reference_wrapper/
Exemplo:
fonte
reference_wrapper
.Uma matriz é implicitamente convertível em um ponteiro, e o ponteiro para referência é ilegal em C ++
fonte
Dado
int& arr[] = {a,b,c,8};
, o que ésizeof(*arr)
?Em qualquer outro lugar, uma referência é tratada como sendo simplesmente a coisa em si,
sizeof(*arr)
deveria simplesmente sersizeof(int)
. Mas isso tornaria o ponteiro da matriz aritmético nessa matriz errado (supondo que as referências não tenham as mesmas larguras são ints). Para eliminar a ambiguidade, é proibido.fonte
struct
cujo único membro é essa referência e descubra ..?Porque, como muitos disseram aqui, referências não são objetos. eles são simplesmente aliases. É verdade que alguns compiladores podem implementá-los como ponteiros, mas o padrão não força / especifica isso. E como as referências não são objetos, você não pode apontar para eles. Armazenar elementos em uma matriz significa que existe algum tipo de endereço de índice (ou seja, apontar para elementos em um determinado índice); e é por isso que você não pode ter matrizes de referências, porque não pode apontar para elas.
Use boost :: reference_wrapper ou boost :: tuple; ou apenas ponteiros.
fonte
Eu acredito que a resposta é muito simples e tem a ver com regras semânticas de referências e como as matrizes são tratadas em C ++.
Resumindo: as referências podem ser consideradas estruturas que não possuem um construtor padrão; portanto, todas as mesmas regras se aplicam.
1) Semântica, as referências não têm um valor padrão. As referências só podem ser criadas fazendo referência a algo. As referências não têm um valor para representar a ausência de uma referência.
2) Ao alocar uma matriz de tamanho X, o programa cria uma coleção de objetos inicializados por padrão. Como a referência não tem um valor padrão, a criação de uma matriz é semanticamente ilegal.
Esta regra também se aplica a estruturas / classes que não possuem um construtor padrão. O seguinte exemplo de código não compila:
fonte
Object
, você apenas tem que ter certeza de inicializar todos eles:Object objects[1] = {Object(42)};
. Enquanto isso, você não pode criar uma matriz de referências, mesmo se inicializar todas elas.Você pode se aproximar bastante dessa estrutura do modelo. No entanto, você precisa inicializar com expressões que apontam para T, em vez de T; e assim, embora você possa criar facilmente um 'fake_constref_array' da mesma forma, não poderá vincular isso a rvalues, como foi feito no exemplo do OP ('8');
-> A = 0 B = 7 X = {0,8,0}
fonte
Um objeto de referência não tem tamanho. Se você escrever
sizeof(referenceVariable)
, ele fornecerá o tamanho do objeto referenciado porreferenceVariable
, não o da própria referência. Ele não tem tamanho próprio, e é por isso que o compilador não pode calcular quanto tamanho a matriz exigiria.fonte
Quando você armazena algo em uma matriz, seu tamanho precisa ser conhecido (uma vez que a indexação da matriz depende do tamanho). De acordo com o padrão C ++, não é especificado se uma referência requer ou não armazenamento; como resultado, a indexação de uma matriz de referências não seria possível.
fonte
struct
, magicamente tudo se torna especificado, bem definido, garantido e de tamanho determinístico. Por que, portanto, existe essa diferença aparentemente totalmente artificial?struct
confere, algumas boas respostas possíveis começam a se sugerir - mas para mim, ninguém o fez ainda, apesar de esse ser um dos desafios imediatos para todos os aspectos comuns. razões pelas quais você não pode usar referências desembrulhadas.Apenas para adicionar a toda a conversa. Como as matrizes requerem locais de memória consecutivos para armazenar o item, por isso, se criarmos uma matriz de referências, não é garantido que elas estejam em local de memória consecutiva, portanto, o acesso será um problema e, portanto, não podemos aplicar todas as operações matemáticas em array.
fonte
Considere uma variedade de ponteiros. Um ponteiro é realmente um endereço; portanto, quando você inicializa a matriz, informa analogicamente ao computador "aloque esse bloco de memória para armazenar esses números X (que são endereços de outros itens)". Então, se você alterar um dos ponteiros, estará apenas mudando para o que ele aponta; ainda é um endereço numérico que está no mesmo local.
Uma referência é análoga a um alias. Se você declarasse uma série de referências, basicamente diria ao computador: "aloque essa bolha amorfa de memória que consiste em todos esses itens diferentes espalhados".
fonte
struct
membro cujo único é uma referência resulta em algo completamente legal, previsível e não amorfo? Por que um usuário deve encapsular uma referência para obter magicamente poderes capazes de array, ou é apenas uma restrição artificial? OMI nenhuma resposta abordou diretamente isso. Suponho que a refutação seja 'O objeto de empacotamento garante que você possa usar a semântica de valor, na forma do objeto de empacotamento, para garantir que você tenha as garantias de valores necessárias, porque, por exemplo, como desambiguar o elemento e o endereço do árbitro' ... É isso que você quis dizer?Na verdade, essa é uma mistura da sintaxe C e C ++.
Deverá quer usar matrizes C puras, que não pode ser de referências, uma vez que são parte de referência C ++ única. Ou você segue o caminho C ++ e usa o
std::vector
oustd::array
classe para sua finalidade.Quanto à parte editada: Embora
struct
seja um elemento de C, você define funções de construtor e operador, que o tornam um C ++class
. Consequentemente, o seustruct
não seria compilado em C puro!fonte
std::vector
oustd::array
também não pode conter referências. O padrão C ++ é bastante explícito que nenhum contêiner pode.