Skip to content

Overload resolution incorrectly considers std::initializer_list with narrowing conversions #152081

@Normal-pcer

Description

@Normal-pcer

Description:

When passing {1, 2.0} to overloaded functions, compilers select the std::initializer_list<int> overload and report a narrowing error. According to the standard, this overload should be excluded from consideration because not all elements can be implicitly converted to X due to narrowing.

Expected behavior:

The conversion to std::initializer_list<int> should be considered invalid during overload resolution per §12.2.4.2.6/5. The overload f(A) should be selected as the only viable candidate.

Actual behavior:

Clang 20.1.0 selects the initializer_list overload and emits:

note: insert an explicit cast to silence this issue
error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]

Minimal Reproduction (Godbolt):

https://godbolt.org/z/fhrM5MYsq

#include <initializer_list>

struct A { int x; double y; };
void f(A) {}                   // #1
void f(std::initializer_list<int>) {} // #2

int main() {
    f({1, 2.0}); // Should select #1 but selects #2 with error
}

Standard Reference (§12.2.4.2.6/5):

"Otherwise, if the parameter type is std​::​initializer_list and all the elements of the initializer list can be implicitly converted to X, the implicit conversion sequence is the worst conversion necessary to convert an element of the list to X..."

Analysis:

  1. The conversion double(2.0) → int requires narrowing
  2. Therefore, the condition "all elements can be implicitly converted to X" fails
  3. The initializer_list<int> overload should be excluded during overload resolution

Affected Standards:

C++11 through C++23 (all show same behavior)

Request:

Adjust overload resolution to properly exclude candidates where narrowing conversions prevent satisfying the "all elements implicitly convertible" requirement in [over.ics.list]p5.

Contrast with Explicit Conversion Behavior (Expected Model):

When replacing narrowing with explicit conversion - which should be excluded similarly - compilers correctly reject the candidate during overload resolution:

#include <initializer_list>

struct Number {
    explicit operator int() const { return 0; } // 显式转换
};

struct A { int x; Number y; };
void f(A) {}                   // #1
void f(std::initializer_list<int>) {} // #2

int main() {
    f({1, Number{}}); // Correctly selects #1 in all compilers
}

This proves:

  1. Compilers properly exclude initializer_list candidates when conversions are invalid (explicit)
  2. Narrowing conversions should follow the same exclusion principle

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:frontendLanguage frontend issues, e.g. anything involving "Sema"questionA question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions