Pergunta

Eu estou trabalhando em código que faz consultas de vizinho mais próximo. Há duas ideias simples que são a base como uma consulta pode usuário para dados de uma pesquisa:

  • mais próximo N pontos para um determinado ponto no espaço.
  • todos os pontos dentro de uma determinada distância.

No meu código, os pontos são colocados em um pointList, eo pointList é um recipiente tem a tarefa de manter o controle dos pontos que foram encontrados na pesquisa.

Agora meu objeto pointList tem um construtor:

PointList( unsigned int maxvals ); // #1

Os próximos dois construtores que eu gostaria de adicionar são os seguintes:

PointList( float maxdist ); // #2
PointList( unsigned int maxvals, float maxdist ); // #3

A minha pergunta é: como posso garantir que meus usuários e o compilador C ++ irá gerar o direito construtor para a pointList e diferencia entre construtores 1 e 2? Devo apenas implementar # 3 e fornecem constantes que definem arbitrária grande valores para maxvals e maxdist? Outra alternativa poderia ser a de escrever um outro sistema de objetos leves que regem a lógica para adicionar pontos à lista, mas que se sente como um exagero para uma idéia tão simples.

Eu estou realmente tentando fazer isso transparente para meus usuários, que são na sua maioria cientistas que aprenderam C ++, por vezes, sem o benefício da educação formal. Obrigado!

Foi útil?

Solução

Resolução de sobrecarga para tipos inteiros acontecer em duas categorias, o que pode ser muito grosseiramente resumida a

  • Promoção: Esta é uma conversão de tipos menores que int para int ou unsigned int, dependendo se int pode armazenar todos os valores do tipo de fonte.
  • Conversão:. Esta é uma conversão de qualquer tipo inteiro para outro tipo inteiro

Semelhante, a conversão para tipos de ponto flutuante acontecer em duas categorias

  • Promoção: Esta é uma conversão de float para double
  • Conversão: Esta é uma conversão a partir de qualquer tipo de ponto flutuante para outro tipo de ponto flutuante

E há uma conversão de inteiro para flutuante ou de volta. Este é classificado como uma conversão, em vez de uma promoção. Uma promoção está classificada melhor do que uma conversão, e em que é necessária apenas uma promoção, nesse caso, será preferido. Assim, você pode usar os seguintes construtores

PointList( int maxVals );
PointList( unsigned int maxVals );
PointList( long maxVals );
PointList( unsigned long maxVals );

PointList( double maxDist );
PointList( long double maxDist );

Para qualquer tipo integer, este deve selecionar o primeiro grupo de construtor. E para qualquer tipo de ponto flutuante, este deve selecionar o segundo grupo de construtores. Seus dois originais construtores poderia facilmente resultar em uma ambigüidade entre float e unsigned int, se você passar um int, por exemplo. Por outro lado, dois construtor argumento, você pode ir com sua solução, se quiser.


Dito isto, gostaria de usar uma função de fábrica também, porque decidir sobre o tipo o significado do parâmetro é bastante frágil que eu penso. A maioria das pessoas seria de esperar o seguinte resultado para igualar

PointList p(floor(1.5));
PointList u((int)1.5);

Mas isso resultaria em um estado diferente de coisas.

Outras dicas

Por que não usar métodos de fábrica em vez de construtores? métodos de fábrica têm a vantagem de nomes customizáveis.


static PointList createNearestValues(unsigned int maxvals) {}
static PointList createByDistance(float maxdist) {}

Considere o uso verdadeiros typedefs . É um pouco mais de esforço por parte do seu código de cliente, mas você é exatidão garantida.

Chamada pointList (10) para o primeiro e pointList (10f) para o segundo.

Para o segundo, você também pode usar 10.0.

Se construtores # 1 e # 2 estão presentes o construtor correto será chamado se o valor que você inserir é de float ou int e nenhuma conversão deve ocorrer. Então, basta garantir que você faça os tipos de números que você usa para chamar explícita (ou seja, 1f e 1). O construtor # 3 não parecem ser muito de uma opção, uma vez que não é realmente necessário e que os usuários apenas confundir as de seu código. Se você precisar de valores padrão para qualquer número que você poderia usar

PointList(int max, float max=VALUE)

e

PointList(float max, int max=VALUE)

Mais uma vez: isso parece fazer mais mal que o código em termos de legibilidade do código

.

Este está chamando para uma boa leitura em Overload resolução .

Eu definitivamente utilizar explícitas construtores. No exemplo, o inteiro sem sinal não converter implicitamente.

class A
{
public:
    explicit A(float f){}
    explicit A(int i){}
};

void test(){
    unsigned int uinteger(0);
    A a1(uinteger);        //Fails, does not allow implicit conversions

    A a2((float)uinteger); //OK, explicit conversion

    float f(0.0);
    A a3(f);               //OK

    int integer(0);
    A a4(integer);         //OK
}

A mensagem de erro é bastante fácil de entender:

: error C2668: 'A::A' : ambiguous call to overloaded function
: could be 'A::A(int)'
: or       'A::A(float)'
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top