Переопределенный и неоднозначный вызов функций имеет параметр массива - PullRequest
1 голос
/ 30 октября 2019

Я хочу увидеть разницу между массивом и параметром ссылки на массив, и я получил переопределенную ошибку и неоднозначную ошибку. Я не понимаю, почему компилятор не может сказать им:

#include "stdafx.h"
#include <iostream>
#include <string>

using namespace std;

typedef int arrTen[10];

void fun(int arr[]) { 
   cout << "arr[] called" << endl;
}

void fun(arrTen arr) {
   cout << "arrTen called" << endl;
   //cout << end(arr) - begin(arr) << endl;
}

void fun(arrTen &arr) {
   cout << "arrTen reference called" << endl;
   cout << end(arr) - begin(arr) << endl;
}

int main()
{
   int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
   fun(arr); //ambiguous call to overloaded function

   return 0;
}

сообщение об ошибке:

Demo.cpp
demo.cpp(24): error C2084: function 'void fun(int [])' already has a body
demo.cpp(20): note: see previous definition of 'fun'
demo.cpp(37): error C2668: 'fun': ambiguous call to overloaded function
demo.cpp(29): note: could be 'void fun(arrTen (&))'
demo.cpp(24): note: or       'void fun(int [])'
demo.cpp(37): note: while trying to match the argument list '(int [10])'
  1. Кажется fun(int arr[])и fun(arrTen arr) переопределены. Я не знаю, почему параметр точки массива равен параметру массива.

  2. , когда я закомментирую fun(int arr[]), fun(arr) - это неоднозначный вызов. Почему компилятор не может сказать, что я передал ссылку на fun?

Ответы [ 4 ]

2 голосов
/ 30 октября 2019

Когда вы объявляете аргумент функции, используя синтаксис массива (с []), компилятор обрабатывает его как указатель .

Т.е. void fun(int arr[]) анализируется как void fun(int* arr).

То, что массив является псевдонимом типа, созданным typedef, не имеет значения, он все равно будет анализироваться как указатель.

Это означает, что функция принимает int [] и arrTen аргументы одинаковы.


Что касается неоднозначности, обе функции перегружаются (та, которая берет указатель, и та, которая ссылается на arrTen), одинаково действительны, и компилятор не может выбратькакой позвонить.

1 голос
/ 30 октября 2019

Массивы распадаются на указатели, поэтому есть неоднозначность - но вы можете получить ссылку на массив из 10 int с, например:

void fun(int (&arr)[10]) {
    std::cout << std::end(arr) - std::begin(arr) << "\n";
}

Для более общегоподход, принимая массивы любого типа и размера:

#include <iostream>
#include <iterator>

template<typename T, size_t N>
void fun(T (&arr)[N]) {
    std::cout << "called with an array of " << N << " elements\n";
    std::cout << std::end(arr) - std::begin(arr) << "\n";
}

int main() {
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    fun(arr);
}
1 голос
/ 30 октября 2019

Эти две функции

void fun(int arr[]) { 
   cout << "arr[] called" << endl;
}

void fun(arrTen arr) {
   cout << "arrTen called" << endl;
   //cout << end(arr) - begin(arr) << endl;
}

имеют тот же тип, что и

void fun( int  *arr);

, поскольку компилятор неявно корректирует параметр, имеющий тип массива, для указания указателя на тип элемента.

Таким образом, этот код нарушает правило единого определения.

Чтобы прояснить, рассмотрите эти объявления функций

void fun( int arr[100] );
void fun( int arr[10] );
void fun( int arr[1] );
void fun( int arr[] );
void fun( int *arr );

Все они объявляют одну и ту же функцию и все эти объявлениямогут быть включены в модуль компиляции, хотя они являются избыточными. Но у функции должно быть только одно определение.

С другой стороны, компилятор также не может выбирать между двумя функциями, которые принимают аргумент по ссылке или по значению.

Вы можете сделать одну функцию спостоянный параметр, такой как

void fun( const arrTen arr) {
   cout << "arrTen called" << endl;
   //cout << end(arr) - begin(arr) << endl;
}

В этом случае будет вызвана функция, которая принимает аргумент по ссылке.

0 голосов
/ 30 октября 2019
typedef int arrTen[10];

int main()
{
   int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    arrTen arr1;

   return 0;
}

это печать typeid () arr и arrTen

(gdb) p typeid (arr))
не удалось найти символ typeinfo для 'int [10]'
(gdb) p typeid (arr1))
не удалось найти символ typeinfo для' int [10] '

, что означает то же самое для компилятора и почему выесть ошибка

...