O que o operador mais unário faz?


86

O que o operador mais unário faz? Existem várias definições que eu encontrei ( aqui e aqui ), mas ainda não tenho ideia de para que ela seria usada. Parece que não faz nada, mas tem um motivo para isso, certo?


3
Acho que a razão histórica está gravemente subestimada.
Wolf

3
Uma pergunta com três tags de idiomas diferentes é bastante ambígua / ruim! As respostas são muito diferentes para C # (sobrecarregável) e C (sem sobrecarga) e C ++ (sobrecarregável, mas herda isso de C e, portanto, suas propriedades também).
legends2k

Eu gostaria de adicionar um link para as 10 principais falhas do C # de Eric Lippert. Você encontrará o operador plus unário nas menções honrosas: informit.com/articles/article.aspx?p=2425867 Ele basicamente diz que deveria ser removido ou nunca deveria ter sido adicionado.
Noel Widmer

Respostas:


57

Ele está lá para ser sobrecarregado se você sentir necessidade; para todos os tipos predefinidos, é essencialmente um ambiente autônomo.

Os usos práticos de um operador aritmético unário no-op são bastante limitados e tendem a se relacionar às consequências do uso de um valor em uma expressão aritmética, em vez do próprio operador. Por exemplo, ele pode ser usado para forçar o alargamento de tipos integrais menores para int, ou garantir que o resultado de uma expressão seja tratado como um rvalue e, portanto, não compatível com um constparâmetro sem referência. Afirmo, no entanto, que esses usos são mais adequados para codificar golfe do que legibilidade. :-)


7
Isso não é verdade, como vários exemplos abaixo indicam.
jkerian

3
Ok, vou acreditar que ele tem alguns usos, mas a maioria dos usos discutidos abaixo está relacionada ao fato de que é uma expressão numérica construída usando um operador no-op: por exemplo, promover para inte resultar em um rvalue são efeitos da expressão -ness, não do próprio operador +.
Jeffrey Hantin,

118

Na verdade, mais unário faz alguma coisa - até mesmo em C. Ele executa as conversões aritméticas usuais no operando e retorna um novo valor, que pode ser um inteiro de largura maior. Se o valor original era um inteiro sem sinal de largura menor que int, ele também será alterado para um signedvalor.

Normalmente, isso não é tão importante, mas pode ter um efeito, por isso é não uma boa idéia usar mais unário como uma espécie de "comentário" denotando que um inteiro é positivo. Considere o seguinte programa C ++:

void foo(unsigned short x)
{
 std::cout << "x is an unsigned short" << std::endl;
}

void foo(int x)
{
 std::cout << "x is an int" << std::endl;
}

int main()
{
 unsigned short x = 5;
 foo(+x);
}

Isso exibirá "x é um int".

Portanto, neste exemplo, mais unário criou um novo valor com um tipo e sinalização diferentes .


5
se você está escrevendo um código que produz um determinado resultado quando recebe um curto e um int que compara igual, então provavelmente você tem um problema diferente
Lie Ryan

1
Obrigado, isso deixa claro (nota: em C, não consegui fazer o exemplo funcionar, pois não consigo sobrecarregar a função foo)
Binarian

o que significa dizer an integer of greater width?
yekanchi

neste contexto, "largura" refere-se ao número de bytes de armazenamento associados ao valor.
giles

41

Da segunda edição K&R:

O unário + é novo no padrão ANSI. Foi adicionado para simetria com o unário -.


6
Absolutamente. * Este é o motivo histórico. C ++ teve que adaptá-lo, então teve que lidar com a sobrecarga.
Wolf

37

Eu vi isso ser usado para maior clareza, para enfatizar o valor positivo como distinto de um valor negativo:

shift(+1);
shift(-1);

Mas esse é um uso muito fraco. A resposta é definitivamente sobrecarregadora.


8
Eu fiz isso também, especialmente ao lidar com vetores comovec3(+1,-1,-1)
mpen

28

Uma coisa que o unário integrado +faz é transformar lvalue em rvalue. Por exemplo, você pode fazer isso

int x;
&x;

mas você não pode fazer isso

&+x;

:)

PS "Sobrecarga" definitivamente não é a resposta certa. Unário +foi herdado de C e não há sobrecarga de operador no nível do usuário em C.


14

A principal coisa que unário + realiza é a promoção de tipo para um int para tipos de dados menores que o int. Isso pode ser muito útil se você estiver tentando imprimir dados de caracteres usando std::coutcomo dados numéricos.

char x = 5;
std::cout << +x << "\n";

é muito diferente de

char x=5;
std::cout << x << "\n";

Também está disponível para sobrecarga, mas na prática sua sobrecarga deve ser quase um NOP.


12

Se você precisar imprimir o valor numérico de bytes brutos (por exemplo, pequenos números armazenados como char) para depuração ou qualquer outro motivo, unário + pode simplificar o código de impressão. Considerar

char c = 42;
cout << c << endl;           // prints "*\n", not what you want in this case
cout << (int)c << endl;      // prints "42\n", ok
cout << +c << endl;          // prints "42\n", much easier to type

Este é apenas um exemplo rápido. Tenho certeza de que há outros momentos em que unário + pode ajudar a tratar seus bytes mais como números em vez de como texto.


4

Um boato histórico. O comitê de padronização do C99 também achou que os usos existentes do plus unário eram bastante raros, conforme evidenciado por considerarem reutilizá-lo para obter outro recurso na linguagem: a inibição da avaliação do tempo de tradução de expressões constantes de ponto flutuante. Consulte a seguinte citação da justificativa C, seção F.7.4:

Uma versão anterior desta especificação permitia a aritmética da constante de tempo de tradução, mas capacitava o operador unário +, quando aplicado a um operando, para inibir a avaliação de tempo de tradução de expressões constantes.

No final, a semântica foi invertida, com a avaliação do tempo de execução aplicada na maioria dos contextos (pelo menos até a regra "como se") e a capacidade de impor a avaliação do tempo de tradução pelo uso de inicializadores estáticos. Observe que a principal diferença está na ocorrência de exceções de ponto flutuante e outras configurações de arredondamento ou precisão de ponto flutuante, quando presentes.


3

Não muito. O argumento geral para permitir a sobrecarga de operator+()é que definitivamente existem usos no mundo real para sobrecarga operator-(), e seria muito estranho (ou assimétrico) se você permitisse a sobrecarga, operator-()mas não permitisse operator+().

Acredito que li esse argumento de Stroustrop pela primeira vez, mas não tenho meus livros comigo para verificá-lo. Eu posso estar errado.


3

Unary plus estava presente em C, onde não fazia absolutamente nada (muito parecido com a autopalavra - chave). Para não tê-lo, Stroustrup teria que introduzir uma incompatibilidade gratuita com C.

Uma vez em C ++, era natural permitir uma função de sobrecarga, assim como o menos unário, e Stroustrup poderia tê-la introduzido por esse motivo se já não estivesse lá.

Então, isso não significa nada. Pode ser usado como uma espécie de decoração para fazer as coisas parecerem mais simétricas, usando +1,5 em vez de -1,5 por exemplo. Em C ++, ele pode ser sobrecarregado, mas será confuso se operator+()fizer alguma coisa. Lembre-se da regra padrão: ao sobrecarregar operadores aritméticos, faça coisas como os ints.

Se você está procurando um motivo para ele estar ali, encontre algo sobre a história inicial de C. Suspeito que não houve um bom motivo, já que C não foi realmente projetado. Considere a autopalavra - chave inútil (presumivelmente em contraste com static, agora sendo reciclada em C ++ 0x), e a entrypalavra - chave, que nunca fez nada (e depois foi omitida em C90). Há um famoso e-mail em que Ritchie ou Kernighan dizem que, quando perceberam que a precedência do operador tinha problemas, já havia três instalações com milhares de linhas de código que eles não queriam quebrar.


1
A única sobrecarga não aritmética que vi que faz sentido estava em expressões regulares ou gramáticas, onde (+ termo) significa um ou mais tems. (Que é a sintaxe de expressão regular bastante padrão)
Michael Anderson,

Sobre entry: ( stackoverflow.com/q/254395/153285 ). Hoje em dia, se você quiser vários pontos de entrada, basta usar chamadas de cauda e otimização guiada por perfil.
Potatoswatter

Acredito que mesmo em C99, dado extern volatile int foo;, um compilador dado a instrução +foo;seria necessário para realizar uma leitura do endereço indicado em qualquer plataforma onde qualquer meio possa existir para determinar que a leitura ocorreu. Não tenho certeza de que isso seria necessário se a instrução fosse apenas "foo", embora muitos compiladores façam isso como cortesia.
supercat

2

Não posso citar nenhuma fonte para isso, mas entendi que é para promoção explícita de tipo, o que implica conversão de tipo sem perdas. Isso o coloca no topo da hierarquia de conversão,

  • Promoção: new_type operator+(old_type)
  • Conversão: new_type(old_type)
  • Fundida: operator(new_type)(old_type)
  • Coerção: new_type operator=(old_type)

Claro, isso é da minha interpretação de uma nota em um dos manuais c / c ++ da Microsoft (realmente antigos) que li há cerca de 15 anos, então aceite-o com cautela.


1
#include <stdio.h>
int main()
{
    unsigned short x = 5;
    printf ("%d\n",sizeof(+x)); 
    printf ("%d\n",sizeof(x)); 
    return 0;
}

Conforme mostrado no exemplo acima, o + unário realmente muda o tipo, tamanho 4 e 2, respectivamente. Estranho que a expressão + x seja de fato calculada no tamanho de, achei que não fosse. Talvez seja devido ao fato de sizeof ter a mesma prioridade que o unário +.


-1

Suponho que você possa usá-lo para sempre tornar um número positivo. Basta sobrecarregar o operador + unário para ser abs. Não vale a pena confundir seus colegas desenvolvedores, a menos que você realmente queira ofuscar seu código. Então funcionaria bem.


Isso faria com que não fosse o oposto de menos unário, o que seria confuso, a menos que você também sobrecarregue menos unário para ser o abdômen negativo, o que tornaria todos os tipos de matemática estranhos
Davy8

Uhh, sim. É por isso que sugeri não fazer isso.
Patrick,

1
@ Davy8: O que o faz pensar que mais unário é atualmente o "oposto" de menos unário? Qual é o "oposto" do operador de complemento bit a bit ~? Não tenho certeza de qual é a sua definição de "oposto", mas suspeito que seja tendenciosa pela experiência do que o positivo unário e o negativo unário fazem atualmente.
ndkrempel

-1

EDIT Reescrever completamente, porque eu estava muuuuuuito longe da minha resposta original.

Isso deve permitir que você trate a declaração explícita de seu tipo como um valor positivo (acho que na maioria das operações não matemáticas). Parece que a negação seria mais útil, mas acho que aqui está um exemplo de onde pode fazer a diferença:

public struct Acceleration
{
    private readonly decimal rate;
    private readonly Vector vector;

    public Acceleration(decimal rate, Vector vector)
    {
        this.vector = vector;
        this.rate = rate;
    }

    public static Acceleration operator +(Acceleration other)
    {
        if (other.Vector.Z >= 0)
        {
            return other;
        }
        return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
    }

    public static Acceleration operator -(Acceleration other)
    {
        if (other.Vector.Z <= 0)
        {
            return other;
        }
        return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
    }

    public decimal Rate
    {
        get { return rate; }
    }

    public Vector Vector
    {
        get { return vector; }
    }
}

Isso não me parece uma operação unária. Leva dois argumentos (abril e maio) então seria binário.
BlueMonkMN

Isso é mais binário. O mais unário é apenas "+1" ou algo parecido, sem operando à esquerda.
Jeffrey Hantin,

foi mal. esqueci meu CS101. fixo.
Michael Meadows,

3
Se eu encontrasse esse tipo de sobrecarga no código de produção, com certeza iria marcá-lo como um bug e corrigi-lo o mais rápido possível. A semântica de +não é tornar um valor positivo, mas deixar seu sinal inalterado.
Arturo Torres Sánchez

-1

simplesmente o usado para convencer quais números são positivos

por exemplo;

int a=10;
System.out.println(+x);// prints 10(that means,that number 10 multiply by +1,{10*+1})

//if we use unary minus

int a=10;
System.out.println(-x);//prints -10(that means,that number 10 multiply by +1,{10*-1})
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.