metodo - const usage c++



Atribuindo função ao ponteiro de função, correção do argumento const? (2)

Eu estou aprendendo as noções básicas de C ++ e OOP na minha universidade agora. Não tenho 100% de certeza de como um ponteiro de função funciona ao atribuir funções a eles. Eu encontrei o seguinte código:

void mystery7(int a, const double b) { cout << "mystery7" << endl; }
const int mystery8(int a, double b) { cout << "mystery8" << endl; }

int main() {
    void(*p1)(int, double) = mystery7;            /* No error! */
    void(*p2)(int, const double) = mystery7;
    const int(*p3)(int, double) = mystery8;
    const int(*p4)(const int, double) = mystery8; /* No error! */
}

Pelo que entendi, as atribuições p2 e p3 são boas, pois os tipos de parâmetros da função correspondem e a constância está correta. Mas por que as atribuições p1 e p4 não dão certo? Não deveria ser ilegal associar const double / int a non-const double / int?


Answer #1

De acordo com o padrão C ++ (declarações Overloadable C ++ 17, 16.1)

(3.4) - Declarações de parâmetros que diferem apenas na presença ou ausência de const e / ou volátil são equivalentes. Ou seja, os constantes e tipos de especificação voláteis para cada tipo de parâmetro são ignorados ao determinar qual função está sendo declarada, definida ou chamada.

Assim, no processo de determinação do tipo de função, o qualificador const, por exemplo, do segundo parâmetro da declaração de função abaixo, é descartado.

void mystery7(int a, const double b);

e o tipo de função é void( int, double ) .

Considere também a seguinte declaração de função

void f( const int * const p );

É equivalente à seguinte declaração

void f( const int * p );

É a segunda const que torna o parâmetro constante (ou seja, declara o próprio ponteiro como um objeto constante que não pode ser reatribuído dentro da função). A primeira const define o tipo do ponteiro. Não é descartado.

Preste atenção ao fato de que, no Padrão C ++, é usado o termo "referência const", as próprias referências não podem ser constantes em relação aos ponteiros. Essa é a seguinte declaração

int & const x = initializer;

está incorreto.

Enquanto esta declaração

int * const x = initializer;

está correto e declara um ponteiro constante.


Answer #2

Existe uma regra especial para argumentos de função passados ​​por valor.

Embora const sobre eles afetará seu uso dentro da função (para evitar acidentes), é basicamente ignorado na assinatura. Isso porque a const de um objeto passado por valor não tem efeito algum sobre o objeto original copiado do site de chamada.

Isso é o que você está vendo.

(Pessoalmente eu acho que essa decisão de projeto foi um erro; é confuso e desnecessário! Mas é o que é. Note que vem da mesma passagem que silenciosamente muda o void foo(T arg[5]); void foo(T* arg); então já tem muita besteirinha aqui que nós temos que lidar!)

Lembre-se, porém, que isso não apaga apenas qualquer const no tipo de tal argumento. Em int* const o ponteiro é const , mas em int const* (ou const int* ) o ponteiro não é const mas é uma const . Apenas o primeiro exemplo se refere à const do próprio ponteiro e será removido.

[dcl.fct]/5 O tipo de uma função é determinado usando as seguintes regras. O tipo de cada parâmetro (incluindo pacotes de parâmetros de função) é determinado a partir de seu próprio decl-specifier-seq e declarator. Após determinar o tipo de cada parâmetro, qualquer parâmetro do tipo “array of T ” ou do tipo de função T é ajustado para “pointer to T ”. Depois de produzir a lista de tipos de parâmetros, quaisquer qualificadores cv de nível superior que modifiquem um tipo de parâmetro são excluídos ao formar o tipo de função . A lista resultante de tipos de parâmetros transformados e a presença ou ausência de reticências ou um pacote de parâmetros de função é a lista de tipos de parâmetros da função. [Nota: Esta transformação não afeta os tipos dos parâmetros. Por exemplo, int(*)(const int p, decltype(p)*) e int(*)(int, const int*) são tipos idênticos. - nota final





function-declaration