Skip to content

Clang considers fold expanded constraint ambiguous when it shouldn't be #135190

@brevzin

Description

@brevzin

Example (from StackOverflow) using C++26's ability to order constraints involving fold expressions (P2963):

template <class T> inline constexpr bool is_integral_v = false;
template <> inline constexpr bool is_integral_v<int> = true;

template <class T> inline constexpr bool is_floating_point_v = false;
template <> inline constexpr bool is_floating_point_v<double> = true;

template <class T> inline constexpr bool is_arithmetic_v = false;
template <> inline constexpr bool is_arithmetic_v<int> = true;
template <> inline constexpr bool is_arithmetic_v<double> = true;

#if WHICH
template <class T> concept floating_point = is_floating_point_v<T>;
template <class T> concept integral = is_integral_v<T>;
template <class T> concept arithmetic = floating_point<T> or integral<T>;
#else
template <class T> concept arithmetic = is_arithmetic_v<T>;
template <class T> concept floating_point = arithmetic<T> and is_floating_point_v<T>;
#endif

// ------------------------------------

template <arithmetic... Ts>
constexpr int f() {
  return 1;
}

template <floating_point... Ts>
constexpr int f() {
  return 2;
}

static_assert(f<int>() == 1);     // ok
static_assert(f<double>() == 2);  // ok

// ------------------------------------

template <class... Ts>
  requires(arithmetic<Ts> && ...)
constexpr int g() {
  return 1;
}

template <class... Ts>
  requires(floating_point<Ts> && ...)
constexpr int g() {
  return 2;
}

static_assert(g<int>() == 1);     // ok
static_assert(g<double>() == 2);  // ok


// ------------------------------------

template <class... Ts>
concept all_arithmetic = (arithmetic<Ts> && ...);

template <class... Ts>
concept all_floating_point = (floating_point<Ts> && ...);

template <class... Ts>
  requires all_arithmetic<Ts...>
constexpr int h() {
  return 1;
}

template <class... Ts>
  requires all_floating_point<Ts...>
constexpr int h() {
  return 2;
}

static_assert(h<int>() == 1);     // ok
static_assert(h<double>() == 2);  // ambiguous with either definition

// ------------------------------------

Either way of defining floating_point such that it subsumes arithmetic leads to g<double>() being valid but h<double>() being ambiguous, but both should be equivalent.

Metadata

Metadata

Assignees

Labels

c++26clang:frontendLanguage frontend issues, e.g. anything involving "Sema"confirmedVerified by a second party

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions