Dicas para jogar golfe em C ++


48

Que dicas gerais você tem para jogar golfe em C ++? Estou procurando idéias que possam ser aplicadas para codificar problemas de golfe em geral que sejam pelo menos um pouco específicos para C ++ (por exemplo, "remover comentários" não é uma resposta). Poste uma dica por resposta.


4
Muitas dicas para jogar golfe em C também são aplicáveis ​​ao C ++; portanto, suponha que os leitores estejam familiarizados com essa pergunta; poste aqui somente se você tiver algo que também não seja uma dica de golfe em C válida.
Toby Speight

@TobySpeight Provavelmente porque eles têm o mesmo URL além do ID da pergunta.
NoOneIsHere 5/17

C e C ++, mesmo que não sejam do tipo 'golfe', são corretos e fáceis (se considerarmos o subconjunto certo de C ++)
RosLuP

Respostas:


24

O operador condicional ternário ?:muitas vezes pode ser usado como um carrinho na de simples if- elsedeclarações em uma economia considerável.

É de valor especial, pois pode ser usado para selecionar valores alternativos como em

#include <iostream>
#include <cstdlib>
int main(int c, char**v){
  int o=0,e=0,u;
  while(--c) ((u=atoi(v[c]))%2?o:e)+=u;
  std::cout << "Sum of odds " << o <<std::endl
            << "Sum of evens " << e <<std::endl;
}

ainda não executou o código, mas acho que não funciona da maneira que você diz. ((u = atoi (v [c]))% 2? o: e) + = u não faz nada além de adicionar o valor u à expressão à esquerda que obtém o valor o ou e, mas as variáveis ​​o e e permanecem inalterados para que eles sempre sejam 0. verifique o código para ver o que acontece. você deve usar endereços para fazer o trabalho
Bogdan Alexandru

4
@BogdanAlexandru Er ... execute-o. Realmente funciona. O valor da expressão entre parênteses é uma referência a um ou outro de ee o. Observe que isso é diferente de como esse operador trabalha em c, onde esse truque não funciona porque não pode ser um valor l.
dmckee

Substitua std::endlcom '\n'que economiza 5 caracteres
Mukul Kumar

3
@MukulKumar Bem, sim. Mas, com o objetivo de demonstrar essa dica, deixei tudo, exceto o ternário-condicional, que não jogava golfe para maior clareza.
dmckee

22

Às vezes, você pode salvar dois caracteres usando o fato de que as variáveis ​​estáticas de duração do armazenamento (que incluem especialmente todas as variáveis ​​de escopo global) são automaticamente inicializadas com zero no início (ao contrário das variáveis ​​automáticas nas quais você não tem essa garantia). Então, ao invés de

int main()
{
  int a=0;
  // ...
}

você pode escrever

int a;
int main()
{
  // ...
}

+1, mas definitivamente uma prática ruim
mondlos

@mondlos: Golfe implica basicamente más práticas.
celtschk

15

Alguns compiladores (por exemplo, GCC) suportam constantes de vários caracteres . Isso pode salvar alguns caracteres quando um valor inteiro grande é necessário. Exemplo:

int n='  ';

O valor é específico da implementação. Normalmente, o valor de 'ab'é 256*'a'+'b'ou 'a'+256*'b'. Você pode especificar até 4 caracteres entre as aspas.


3
GCC? Você quer dizer g ++ ?
Nathan Osman

6
@George Edison: GCC representa o GNU Compiler Collection , que abrange todas as suas interfaces, incluindo aqueles para C, C ++, Go, etc.
Joey Adams

@ Joey: Eu sei, mas também é o nome do GNU C Compiler.
22611 Nathan Osman

25
@ George: O compilador GNU C é chamado gcc, não GCC.
Fredoverflow

É melhor lembrar que eu poderia esquecer.

12

Um que eu achei útil:

Aproveitando o fato de que valores diferentes de zero são avaliados trueem expressões booleanas e que são x&&yavaliados x*yquando se lida com booleanos

(x!=0 && y!=0)

avalia como

(x*y)

Você só precisa estar ciente dos estouros, como indicado abaixo.


2
Tecnicamente é x!=0 && y!=0. Mas ao usar a multiplicação, você precisa ter cuidado com os estouros. Ao usar números inteiros de 32 bits, x = y = 65536 (e várias outras combinações de potências de dois) também produziriam x * y = 0 .
Martin Ender

Sim está certo. Usei-o como limites de uma matriz bidimensional, verifique aqui: codegolf.stackexchange.com/a/37571/31477 onde isso não importava. Vou editar esses pontos.
Baldrickk

11
Observe, no entanto, que &&possui um comportamento de curto-circuito que *falta. Por exemplo, você não pode substituir i++!=0&&j++!=0por i++*j++.
celtschk 17/07

@celtschk sim, bom ponto. Mas se você está fazendo puramente a álgebra booleana, ela funciona
Baldrickk

11

Use os seguintes tipos:

u64, s64, u32, s32 (or int)

Para palavras / tipos repetitivos, use #defines:

#define a while

Só vale a pena se você usar whilemuito para compensar os 10 caracteres extras. ( Cerca de 4. )


11
Os tipos u64, s64, u32 e s32 não fazem parte do C ++. Eles podem ser uma extensão não padrão do seu compilador (embora eu nunca os tenha visto).
Celtschk

5
Essas duas dicas seriam melhor colocadas em duas respostas separadas para que possam ser votadas individualmente.
precisa saber é o seguinte


10

Quando possível, altere &&e ||para &e |respectivamente.

Ao usar instruções if simples:

if(<condition>)<stuff>;

pode ser alterado para:

<condition>?<stuff>:<any single letter variable>;

que salva um personagem.


8

Em vez de usar while(1), use for(;;), salvando um caractere :)


8

O uso do operador de vírgula no lugar de chaves de abertura e fechamento pode salvar alguns caracteres, se você tiver uma situação em que suas cláusulas contenham mais de uma instrução:

if(c){x=1;cout<<"Hi";y=2;}else{x=2;cout<<"Bye";y=3;}

vs.

if(c)x=1,cout<<"Hi",y=2;else x=2,cout<<"Bye",y=3;###

Dois caracteres salvos em um IF simples ou três no total para um IF / ELSE.

Como ponto de distinção entre C e C ++, o resultado de uma expressão de vírgula no C ++ como um todo pode ser usado como um valor l ... FWIW.


7

Como os elementos da matriz são armazenados diretamente um após o outro na memória, em vez de algo como isto:

for(int x = 0; x < 25; x++) {
    for(int y = 0; y < 25; y++)
        array[x][y] = whatever;
}

Você pode fazer algo assim:

int* pointer = array;
for(int i = 0; i < 25*25; i++, pointer++)
    *pointer = whatever;

Obviamente, nenhuma das opções acima é jogada no golfe, para facilitar a leitura, mas o uso explícito de ponteiros pode economizar muito espaço.


Não esqueça que você pode cortar todo esse espaço em branco! (Ponta completamente diferente, mas deve ser mencionado)
stokastic

@stokastic Os exemplos não são para serem jogados no golfe, apenas para demonstrar como usar a técnica.
Stuntddude

6
por que não for(int* i=array; i<array+25*25; i++)? Então você só precisa acompanhar uma variável.
Lucas

6

Bastante óbvio, mas se você estiver usando grande parte da biblioteca padrão, using namespace std;poderá salvar alguns caracteres.


5
Se você usar apenas um único nome, mas com bastante frequência, using std::name;pode ser mais curto.
Celtschk

10
Isso só salva caracteres se você usar std::cinco ou mais vezes.
nyuszika7h

6

É útil lembrar que a[i]é o mesmo que *(a+i).

Substitua a[0]por *apara economizar dois caracteres. Além disso, a[i][0]é equivalente a *a[i]e a[0][i]diminui para i[*a]. Portanto, se você estiver codificando um 0índice em sua matriz, provavelmente existe uma maneira melhor.


5

Em vez de escrever grandes potências de 10, use a notação . Por exemplo, a=1000000000é maior que a=1e9. Isso pode ser estendido para outros números, como a=1e9+24é melhor que a=1000000024.


11
Observe que isso não é exatamente equivalente; é necessário converter para tipos inteiros antes de usar. Por exemplo, 1e9/xnão é o mesmo que 1000000000/xou int(1e9)/x.
user202729

5

Você pode usar o operador ternário ?:sem nenhuma expressão no bloco verdadeiro (ele salva um byte)

#include <iostream>

int foo()
{
    std::cout << "Foo\n";
}

int main()
{
    1?foo():0;  // if (true) foo()
    0?:foo();   // if (!false) foo()
}

Veja aqui


5
Parece ser uma extensão GNU e não está no padrão C ++. https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Conditionals.html#Conditionals
ceilingcat 23/16

r? foo (): 0; // se (r) foo () está ok ;;;;; mas Para este r?: foo (); Eu não sei o que
RosLuP

5

Cabeçalho mais curto

Isso é específico do GCC, pode ser extensível a outros compiladores.

Cabeçalho pré-compilado.

No G ++, bits/stdc++.ho cabeçalho pré-compilado consiste em todos os outros cabeçalhos. Se você precisar de import2 diferentes, basta usar isso.

Cabeçalho mais curto.

Todos os cabeçalhos listados em http://en.cppreference.com/w/cpp/header :

classificados em ordem crescente de comprimento.

Alguns deles já são mais longos bits/stdc++.he outros requerem suporte ao C ++ 17. Alguns outros não são suportados pelo TIO G ++ (por razões que não conheço). Filtre-os, temos:

Pode acontecer que alguns deles possam ser substituídos por outros mais curtos. Basta procurar binário se o que você precisa pode ser substituído. Em particular:

cstdio -> ios        (-3 bytes)
algorithm -> regex   (-4 bytes)
vector -> queue      (-1 byte)
string -> map        (-3 bytes)
bitset -> regex      (-1 byte)
numeric -> random    (-1 byte)

4

#importem vez de #includefornecer mais um byte.

Além disso, o caractere de espaço entre #importe cabeçalho não é necessariamente:

#include <map>
// vs
#import<map>

E se você precisar de algo do stdlibcabeçalho, poderá importar qualquer cabeçalho com o contêiner STL (preferível setou map) em vez de cstdlib.


3

Operações aritméticas em booleanos:

Apesar

a*=b>0?.5:-.5

é melhor que

if(b>0)a*=.5;else a*=-.5;

não é tão bom quanto

a*=(b>0)-.5

Além disso, usar #define em qualquer coisa usada muito. Geralmente é mais curto que o uso de funções, pois os nomes dos tipos não são necessários.

Combine as coisas o máximo possível:

a+=a--;

é o mesmo que

a=2*a-1;

Enquanto seus exemplos estiverem corretos, tenha cuidado ao chamar um comportamento indefinido ao usar xcomo lvalue e x++como rvalue. comportamento indefinido e sequência de pontos
ceilingcat

Sim possível a + = a--; tem comportamento indefinido
RosLuP 28/01

3

Use lambdas genéricas como modelos baratos

Para tipos diferentes de int, usá-los como argumentos de função pode ser caro. No entanto, lambdas genéricas foram introduzidas (em C ++ 14?) E permitem que qualquer lambda seja um modelo - o uso autopara os tipos de argumento pode salvar bytes. Comparar:

double f(double x, double y)
[](auto x, auto y)

Lambdas genéricos também são muito convenientes para aceitar iteradores - provavelmente a melhor maneira de aceitar entradas de array em C ++ é [](auto a, auto z), onde ae zsão passados ​​como begin()e end()da matriz / vetor / lista / etc.


2

Na minha primeira tentativa de codificar golf para a tarefa "Subtrair os próximos números" , iniciei da função (58 bytes)

int f(int N, int P){int F;for(F=N;P;F-=++N,P--);return F;}

5 bytes seguros, mudando para lambda e movendo a inicialização para fora de for(53)

[](int N,int P){int F=N;for(;P;F-=++N,P--);return F;}

e, finalmente, depois de mudar forpara while, obtive 51 bytes:

[](int N,int P){int F=N;while(P--)F-=++N;return F;}

O código de teste ungolfed é algo como:

#include <iostream>
int main(void)
{
    int N, P;
    std::cin >> N >> P;
    auto f = [](int N,int P)
    {
        int F = N;
        while (P--)
            F -= ++N;
        return F;
    };
    std::cout << f(N, P) << std::endl;
    return 0;
}

ATUALIZAR:

Na verdade, forpode atingir o mesmo comprimento que while:

[](int N,int P){int F=N;for(;P--;F-=++N);return F;}

2

Meio atrasado para a festa, eu acho ...

Se você deseja transformar uma expressão em -1 e 1 em vez de 0 e 1, em vez disso:

int x;
if (a * 10 > 5)
    x = 1;
else
    x = -1;

fazem isto:

int x = (a * 10 > 5) * 2 - 1;

Pode salvar alguns bytes, dependendo do uso.


Em vez de int x=(a*10>5)*2-1;, você não poderia fazer int x=a*10>5?1:-1;, que é 1 byte menor?
girobuz

2

Se você deseja trocar duas variáveis ​​inteiras aeb, então,

a^=b^=a^=b;

pode ser usado, economizando 5 caracteres do que o modo padrão

a+=b;
b=a-b;
a-=b;

11
Sobre esse caminho padrão. ,tnas entradas criadas anteriormente e, em seguida t=a;a=b;b=t;, já teria sido 3 bytes mais curto que o a+=b;b=a-b;a-=b;. Ainda assim, o seu a^=b^=a^=b;é ainda mais curto do que isso, então +1 de mim. Eu não sei C ++, mas realmente funciona . Como jogador de código Java, estou triste por não parecer funcionar lá . :(
Kevin Cruijssen 14/02

11
@KevinCruijssen Sim, eu deveria ter mencionado C ++, não sei muito sobre java, mas a^=b;b^=a;a^=b;está funcionando bem em java.
joker007 14/02

11
Não há necessidade de mencionar explicitamente C ++. Todas essas dicas são para C ++. :) Como desenvolvedor Java, fiquei curioso para saber se algo semelhante poderia ser feito em Java, mas aparentemente não. a^=b;b^=a;a^=b;de fato funciona, mas é mais longo que o ,t+ t=a;a=b;b=t;. Desculpe por mencionar o Java, pois está fora de tópico aqui. Mas boa dica para codegolfers C ++!
Kevin Cruijssen 14/02

2

Use os recursos internos do GCC em vez de importar

Se você estiver usando um compilador GCC, às vezes é útil usar as funções internas, como __builtin_putsou __builtin_clz. Por exemplo,

44 bytes:

int main(){__builtin_puts("Hello, world!");}`

50 bytes:

#import<cstdio>
int main(){puts("Hello, world!");}

1

Se você estiver usando o C ++ 11 ou mais recente (o que deve ser sempre o caso agora), use autopara tipos complexos, se possível.

Exemplo: 54 bytes em vez de 66

#include<vector>
std::vector<int> f(std::vector<int> l){return l;}
#include<vector>
auto f(std::vector<int> l){return l;}

Além disso, como o desempenho não importa, para alguns desafios, um std::listpode apenas fazer o trabalho por alguns bytes a menos:

#include<list>
auto f(std::list<int> l){return l;}

1

As funções <algorithm>geralmente requerem uma passagem a.begin(),a.end()realmente longa; em vez disso, você pode &a[0],&*end(a)salvar 3 bytes se afor vectorou string.

sort(a.begin(),a.end());
sort(begin(a),end(a));
sort(&a[0],&*end(a));

0

Não use string(""), use "". Ele economiza 8 bytes.


Não é exatamente equivalente. Por exemplo , "" + 'a'is char* + char, que é adição de ponteiro, enquanto std::string("") + 'a'is std::string + char- string concatenação. string()podia funcionar.
precisa saber é o seguinte
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.