Não adora C ++ quando se trata da linha de perguntas "recursos ocultos de"? Achei melhor jogar fora lá. Quais são alguns dos recursos ocultos do C ++?
c++
hidden-features
Craig H
fonte
fonte
Respostas:
A maioria dos programadores C ++ está familiarizada com o operador ternário:
No entanto, eles não percebem que pode ser usado como um lvalue:
que é uma abreviatura para
Use com cuidado :-)
fonte
(value ? function1 : function2)()
.function1
efunction2
forem convertidos implicitamente em ponteiros de função, e o resultado será implicitamente convertido de volta.Você pode colocar URIs na origem C ++ sem erros. Por exemplo:
fonte
goto
, que C ++ tem). Qualquer coisa após duas barras é um comentário. Portanto, comhttp://stackoverflow.com
,http
é um rótulo (você poderia teoricamente escrevergoto http;
) e//stackoverflow.com
é apenas um comentário de fim de linha. Ambos são C ++ legais, então a construção compila. Não faz nada vagamente útil, é claro.goto http;
, na verdade, não segue o URL. :(Os programadores C ++ preferem evitar ponteiros por causa dos bugs que podem ser introduzidos.
O C ++ mais legal que eu já vi? Literais analógicos.
fonte
Eu concordo com a maioria das postagens: C ++ é uma linguagem multiparadigma, então os recursos "ocultos" que você encontrará (além dos "comportamentos indefinidos" que você deve evitar a todo custo) são usos inteligentes de recursos.
A maioria dessas facilidades não são recursos integrados da linguagem, mas sim baseados em bibliotecas.
O mais importante é o RAII , muitas vezes ignorado por anos pelos desenvolvedores C ++ vindos do mundo C. Sobrecarga do operador é frequentemente um recurso mal compreendido que permite comportamento semelhante a array (operador subscrito), operações semelhantes a ponteiros (ponteiros inteligentes) e operações semelhantes a embutidas (multiplicação de matrizes.
O uso de exceção é muitas vezes difícil, mas com algum trabalho, pode produzir código realmente robusto por meio de segurança de exceção especificações de (incluindo código que não falhará, ou que terá recursos semelhantes a um commit que terá sucesso ou reverterá para seu estado original).
O recurso "oculto" mais famoso do C ++ é a metaprogramação de template , uma vez que permite que você tenha seu programa parcialmente (ou totalmente) executado em tempo de compilação em vez de em tempo de execução. No entanto, isso é difícil e você deve ter um domínio sólido sobre os modelos antes de tentar.
Outros fazem uso do paradigma múltiplo para produzir "formas de programação" fora do ancestral C ++, ou seja, C.
Usando functores , você pode simular funções, com a segurança de tipo adicional e com estado. Usando o padrão de comando , você pode atrasar a execução do código. A maioria dos outros padrões de design podem ser implementados de maneira fácil e eficiente em C ++ para produzir estilos de codificação alternativos que não deveriam estar na lista de "paradigmas oficiais de C ++".
Usando modelos , você pode produzir código que funcionará na maioria dos tipos, incluindo aquele que você não pensou a princípio. Você também pode aumentar a segurança de tipo (como um malloc / realloc / free typesafe automatizado). Os recursos do objeto C ++ são realmente poderosos (e, portanto, perigosos se usados descuidadamente), mas mesmo o polimorfismo dinâmico tem sua versão estática em C ++: o CRTP .
Eu descobri que a maioria dos livros do tipo " C ++ Eficaz " de Scott Meyers ou livros do tipo " C ++ Excepcional " de Herb Sutter são fáceis de ler e um tesouro de informações sobre recursos conhecidos e menos conhecidos do C ++.
Entre as minhas preferidas está uma que deve fazer o cabelo de qualquer programador Java erguer-se do horror: Em C ++, a maneira mais orientada a objetos de adicionar um recurso a um objeto é por meio de uma função não amiga de não membro, em vez de um membro função (ou seja, método de classe), porque:
Em C ++, a interface de uma classe é tanto suas funções-membro quanto as funções não-membro no mesmo namespace
funções não-membro não-amigáveis não têm acesso privilegiado ao interno da classe. Como tal, usar uma função de membro em vez de uma função não amiga não membro enfraquecerá o encapsulamento da classe.
Isso nunca deixa de surpreender, mesmo os desenvolvedores experientes.
(Fonte: Entre outros, o Guru on-line da semana de Herb Sutter nº 84: http://www.gotw.ca/gotw/084.htm )
fonte
Uma característica da linguagem que considero estar um tanto oculta, porque nunca tinha ouvido falar dela em todo o meu tempo na escola, é o alias de namespace. Não fui trazido à minha atenção até que encontrei exemplos disso na documentação do boost. Claro, agora que eu sei sobre isso, você pode encontrá-lo em qualquer referência C ++ padrão.
fonte
using
.Não apenas as variáveis podem ser declaradas na parte inicial de um
for
loop, mas também classes e funções.Isso permite várias variáveis de tipos diferentes.
fonte
O operador de matriz é associativo.
A [8] é sinônimo de * (A + 8). Como a adição é associativa, isso pode ser reescrito como * (8 + A), que é um sinônimo de ..... 8 [A]
Você não disse útil ... :-)
fonte
A
não importa. Por exemplo, seA
fosse umchar*
, o código ainda seria válido.Algo que é pouco conhecido é que os sindicatos também podem ser modelos:
E eles também podem ter construtores e funções-membro. Nada que tenha a ver com herança (incluindo funções virtuais).
fonte
From
eTo
for definido e usado de acordo. No entanto, tal união pode ser usada com comportamento definido (To
sendo uma matriz de caracteres não assinados ou uma estrutura compartilhando uma sequência inicial comFrom
). Mesmo se você usá-lo de forma indefinida, ainda pode ser útil para trabalhos de baixo nível. De qualquer forma, este é apenas um exemplo de um modelo de união - pode haver outros usos para um modelo de união.C ++ é uma linguagem multiparadigma, você pode apostar seu último dinheiro na existência de recursos ocultos. Um exemplo entre muitos: metaprogramação de template . Ninguém no comitê de padrões pretendia que houvesse uma sublinguagem completa de Turing que fosse executada em tempo de compilação.
fonte
Outro recurso oculto que não funciona em C é a funcionalidade do unário
+
operador . Você pode usá-lo para promover e degradar todos os tipos de coisasConverter uma enumeração em um inteiro
E seu valor de enumerador, que antes tinha seu tipo de enumeração, agora tem o tipo inteiro perfeito que pode caber em seu valor. Manualmente, você dificilmente conheceria esse tipo! Isso é necessário, por exemplo, quando você deseja implementar um operador sobrecarregado para sua enumeração.
Obtenha o valor de uma variável
Você tem que usar uma classe que usa um inicializador estático da classe sem uma definição fora da classe, mas às vezes ele falha ao vincular? O operador pode ajudar a criar um temporário sem fazer suposições ou dependências de seu tipo
Decompõe uma matriz em um ponteiro
Você quer passar dois ponteiros para uma função, mas simplesmente não funciona? A operadora pode ajudar
fonte
O tempo de vida de temporários limitados a referências constantes é algo que poucas pessoas conhecem. Ou pelo menos é meu conhecimento favorito de C ++ que a maioria das pessoas não conhece.
fonte
Um bom recurso que não é usado com frequência é o bloco try-catch de toda a função:
O uso principal seria traduzir a exceção para outra classe de exceção e relançar, ou traduzir entre exceções e tratamento de código de erro baseado em retorno.
fonte
return
pegar o bloco de função Try, apenas relançar.Muitos sabem da
identity
/id
metafunção, mas há um bom caso de uso para casos não-template: Facilidade de escrita de declarações:Isso ajuda muito a descriptografar declarações C ++!
fonte
template<typename Ret,typename... Args> using function = Ret (Args...); template<typename T> using pointer = *T;
->pointer<function<void,int>> f(pointer<function<void,void>>);
oupointer<void(int)> f(pointer<void()>);
oufunction<pointer<function<void,int>>,pointer<function<void,void>>> f;
Um recurso bastante oculto é que você pode definir variáveis dentro de uma condição if, e seu escopo se estenderá apenas sobre os blocos if e else:
Algumas macros usam isso, por exemplo, para fornecer algum escopo "bloqueado" como este:
Além disso, BOOST_FOREACH o usa sob o capô. Para completar isso, não é apenas possível em um if, mas também em um switch:
e em um loop while:
(e também em uma condição para). Mas não tenho certeza se eles são tão úteis :)
fonte
if((a = f()) == b) ...
, mas essa resposta realmente declara uma variável na condição.for(...; int i = foo(); ) ...;
isto irá percorrer o corpo, desde quei
seja verdadeiro, inicializando-o a cada vez. O loop que você mostra está simplesmente demonstrando uma declaração de variável, mas não uma declaração de variável que atua simultaneamente como uma condição :)Evitando que o operador vírgula chame sobrecargas de operador
Às vezes, você faz uso válido do operador vírgula, mas deseja garantir que nenhum operador vírgula definido pelo usuário atrapalhe, porque, por exemplo, você confia em pontos de sequência entre os lados esquerdo e direito ou deseja ter certeza de que nada interfere com o desejado açao. É aqui que
void()
entra o jogo:Ignore os espaços reservados que coloquei para a condição e o código. O que é importante é o
void()
, o que força o compilador a usar o operador vírgula embutido. Isso pode ser útil ao implementar classes de características, às vezes, também.fonte
Inicialização de array no construtor. Por exemplo, em uma classe, se tivermos uma matriz de
int
como:Podemos inicializar todos os elementos da matriz para seu padrão (aqui, todos os elementos da matriz para zero) no construtor como:
fonte
Oooh, em vez disso, posso fazer uma lista de ódios de animais de estimação:
Do lado positivo
fonte
Você pode acessar dados protegidos e membros de função de qualquer classe, sem comportamento indefinido e com semântica esperada. Continue lendo para ver como. Leia também o relatório de defeito sobre isso.
Normalmente, C ++ proíbe que você acesse membros protegidos não estáticos de um objeto de classe, mesmo se essa classe for sua classe base
Isso é proibido: você e o compilador não sabem para onde a referência realmente aponta. Pode ser um
C
objeto, caso em que a classeB
não tem negócios e não tem nenhuma pista sobre seus dados. Esse acesso só é concedido sex
for uma referência a uma classe derivada ou derivada dela. E poderia permitir que um pedaço de código arbitrário leia qualquer membro protegido simplesmente criando uma classe "descartável" que lê membros, por exemplostd::stack
:Certamente, como você vê, isso causaria muitos danos. Mas agora, os ponteiros de membro permitem contornar essa proteção! O ponto principal é que o tipo de um ponteiro de membro está vinculado à classe que realmente contém o referido membro - não à classe que você especificou ao obter o endereço. Isso nos permite contornar a verificação
E, claro, também funciona com o
std::stack
exemplo.Isso será ainda mais fácil com uma declaração de uso na classe derivada, que torna o nome do membro público e se refere ao membro da classe base.
fonte
Outro recurso oculto é que você pode chamar objetos de classe que podem ser convertidos em ponteiros de função ou referências. A resolução da sobrecarga é feita no resultado deles, e os argumentos são perfeitamente encaminhados.
Elas são chamadas de "funções de chamada substituta".
fonte
Recursos ocultos:
Se uma função lançar uma exceção não listada em suas especificações de exceção, mas a função lançar
std::bad_exception
em sua especificação de exceção, a exceção é convertida emstd::bad_exception
e lançada automaticamente. Dessa forma, você saberá pelo menos que umbad_exception
foi lançado. Leia mais aqui .blocos de teste de função
A palavra-chave template na eliminação da ambiguidade de typedefs em um template de classe. Se o nome de um modelo de especialização membro aparece depois de um
.
,->
ou::
operador, e que tem o nome parâmetros do modelo explicitamente qualificados, o prefixo do nome do modelo de membro com o modelo de palavra-chave. Leia mais aqui .os padrões dos parâmetros da função podem ser alterados em tempo de execução. Leia mais aqui .
A[i]
funciona tão bem quantoi[A]
Instâncias temporárias de uma classe podem ser modificadas! Uma função de membro não const pode ser chamada em um objeto temporário. Por exemplo:
Leia mais aqui .
Se dois tipos diferentes estiverem presentes antes e depois de
:
in na?:
expressão do operador ternário ( ), o tipo resultante da expressão será o mais geral dos dois. Por exemplo:fonte
map::operator[]
cria a entrada se a chave estiver faltando e retorna a referência ao valor da entrada construída por padrão. Então você pode escrever:Estou surpreso com a quantidade de programadores C ++ que não sabem disso.
fonte
.find()
.const map::operator[]
gera mensagens de erro"Colocar funções ou variáveis em um namespace sem nome torna obsoleto o uso de
static
para restringi-los ao escopo do arquivo.fonte
static
em escopo global não está obsoleto de forma alguma. (Para referência: C ++ 03 §D.2)static
use só deve ser usado em um tipo de classe ou função.Definir funções de amigo comuns em modelos de classe requer atenção especial:
Neste exemplo, duas instanciações diferentes criam duas definições idênticas - uma violação direta do ODR
Devemos, portanto, ter certeza de que os parâmetros do modelo do modelo de classe aparecem no tipo de qualquer função amiga definida naquele modelo (a menos que desejemos evitar mais de uma instanciação de um modelo de classe em um arquivo específico, mas isso é bastante improvável). Vamos aplicar isso a uma variação do nosso exemplo anterior:
Isenção de responsabilidade: colei esta seção de Modelos C ++: O Guia Completo / Seção 8.4
fonte
funções void podem retornar valores nulos
Pouco conhecido, mas o código a seguir está bom
Bem como a seguinte aparência estranha
Sabendo disso, você pode tirar vantagem em algumas áreas. Um exemplo: as
void
funções não podem retornar um valor, mas você também não pode simplesmente retornar nada, porque elas podem ser instanciadas com non-void. Em vez de armazenar o valor em uma variável local, o que causará um erro paravoid
, basta retornar um valor diretamentefonte
Leia um arquivo em um vetor de strings:
istream_iterator
fonte
vector<string> V((istream_iterator<string>(cin)), istream_iterator<string>());
- faltando parênteses após o segundo parâmetroVocê pode modelar campos de bits.
Eu ainda não descobri nenhum propósito para isso, mas com certeza me surpreendeu.
fonte
Uma das gramáticas mais interessantes de qualquer linguagem de programação.
Três dessas coisas pertencem uma à outra, e duas são algo totalmente diferente ...
Todos, exceto o terceiro e o quinto, definem um
SomeType
objeto na pilha e o inicializam (comu
nos dois primeiros casos, e o construtor padrão no quarto. O terceiro está declarando uma função que não leva parâmetros e retorna umSomeType
. O quinto está declarando de forma semelhante uma função que leva um parâmetro por valor do tipoSomeType
nomeadou
.fonte
Livrar-se de declarações futuras:
Escrevendo instruções switch com operadores?::
Fazer tudo em uma única linha:
Zerando structs sem memset:
Normalizando / envolvendo valores de ângulo e tempo:
Atribuição de referências:
fonte
FStruct s = {};
é ainda mais curto.main
? Eu sugeririaglobal().main();
e simplesmente esqueceria o singleton ( você pode apenas trabalhar com o temporário, que prolonga sua vida útil )O operador condicional ternário
?:
requer que seu segundo e terceiro operando tenham tipos "agradáveis" (falando informalmente). Mas esse requisito tem uma exceção (trocadilho intencional): o segundo ou o terceiro operando pode ser uma expressão de lançamento (que tem tipovoid
), independentemente do tipo do outro operando.Em outras palavras, pode-se escrever as seguintes expressões C ++ perfeitamente válidas usando o
?:
operadorBTW, o fato de que throw expression é na verdade uma expressão (do tipo
void
) e não uma instrução é outro recurso pouco conhecido da linguagem C ++. Isso significa, entre outras coisas, que o código a seguir é perfeitamente válidoembora não haja muito sentido em fazer dessa maneira (talvez em algum código de modelo genérico isso possa ser útil).
fonte
A regra de dominância é útil, mas pouco conhecida. Ele diz que mesmo se em um caminho não exclusivo através de uma estrutura de classe base, a pesquisa de nome para um membro parcialmente oculto é única se o membro pertencer a uma classe base virtual:
Usei isso para implementar o suporte de alinhamento que descobre automaticamente o alinhamento mais estrito por meio da regra de dominância.
Isso não se aplica apenas a funções virtuais, mas também a nomes de typedef, membros estáticos / não virtuais e qualquer outra coisa. Já vi isso ser usado para implementar características substituíveis em metaprogramas.
fonte
struct C
em seu exemplo ...? Felicidades.