Страницы

Поиск по вопросам

вторник, 25 февраля 2020 г.

Перегрузка конструкторов, какой конструктор будет вызван?

#cpp #language_lawyer


Это UB или есть какое-то правило?

class foo {
public:
    foo (int a, int b) { ... }
    foo (char a, char b) { ... }
};

int main ()
{
    foo bar(1,'2');
}

    


Ответы

Ответ 1



Здесь нет неопределенного поведения, так как здесь вообще нет никакого поведения, так как код не будет компилироваться.:) Здесь имеет место неоднозначность вызова конструктора, так как ни один из конструкторов не является лучше другого для заданных аргументов. Согласно стандарту C++ (13.3.3 Best viable function) ...Given these definitions, a viable function F1 is defined to be a better > function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then... В вашем примере foo (int a, int b) { ... } foo (char a, char b) { ... } //... foo bar(1,'2'); первый параметр первого конструктора "лучше" первого параметра второго конструктора так как не требуется преобразования из типа аргумента к типу параметра первого конструктора. Однако относительно вторых параметров ситуация прямо противоположная, то есть второй параметр второго конструктора "лучше" второго параметра первого конструктора, так как не требуется никакого преобразования из типа аргумента к типу параметра. Следовательно согласно приведенной цитате ни один из конструкторов не лучше другого конструктора для всех своих параметров и заданных аргументов. Это UB или есть какое-то правило? Это называется разрешением перегрузки, и правила выбора компилятором наилучшей функции из перегруженных описаны в стандарте C++. 3 If a best viable function exists and is unique, overload resolution succeeds and produces it as the result. Otherwise overload resolution fails and the invocation is ill-formed.... Дополнение. При определенных опциях компилятор GCC, например, может скомпилировать код, но при этом выдать предупреждение. В этом случае он выберет первый конструктор, так как для его второго параметра достаточно применить к аргументу integral promotion. В то время как для второго конструктора для его первого параметра требуется преобразование аргумента из типа int в тип char А integral promotion имеет "лучший" ранг, чем преобразование (13.3.3.2 Ranking implicit conversion sequences): 4 Standard conversion sequences are ordered by their ranks: an Exact Match is a better conversion than a Promotion, which is a better conversion than a Conversion. Неоднозначность можно было бы (и следовало) устранить посредством явного преобразования, либо написав foo bar( 1, int( '2' ) ); и тогда будет вызван первый конструктор, либо написав foo bar( char( 1 ), '2' ); и тогда будет вызван второй конструктор.

Ответ 2



Да, это UB. Если ее скомпилировать g++, то будет использован конструктор foo (int a, int b) и вылезет warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second Clang отказался компилировать, выдав ошибку, майкрософтовский тоже, то есть то, какой конструктор будет выбран, зависит от реализации компилятора (g++ выбирает по принципу какое из плохих преобразований лучше, хотя как он решает, я не очень понял).

Комментариев нет:

Отправить комментарий