abseil / abseil/abseil-cpp

[Bug]: Defining both AbslFormatConvert and AbslStringify leads to ambiguous function call

Abierto
#1,966 0 comentarios 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
C++
Estrellas
18.1k
Forks
3.2k
Merge medio
20 h 36 min
PR fusionados (30 d)
1

Descripción

### Describe the issue

If both AbslStringify and AbslFormatConvert are defined for a custom type (https://abseil.io/docs/cpp/guides/format#user-defined-formats), compilation fails when calling StrFormat.

For example, given

```c++
struct Point {
template
friend void AbslStringify(Sink& sink, const Point& p) {
absl::Format(&sink, "(%d, %d)", p.x, p.y);
}

friend absl::FormatConvertResult
AbslFormatConvert(const Point& p,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s) {
absl::Format(s, "(%d, %d)", p.x, p.y);
return {true};
}

int x;
int y;
};

TEST(CustomStringify, Works) {
EXPECT_EQ(absl::StrFormat("%v", Point{1, 2}), "(1, 2)");
}
```

compilation fails with

```
external/abseil-cpp+/absl/strings/internal/str_format/arg.h:426:31: error: call to 'FormatConvertImpl' is ambiguous
426 | using ConvResult = decltype(str_format_internal::FormatConvertImpl(
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
external/abseil-cpp+/absl/strings/str_format.h:281:26: note: in instantiation of function template specialization 'absl::str_format_internal::ArgumentToConv' requested here
281 | str_format_internal::ArgumentToConv()...>;
| ^
external/abseil-cpp+/absl/strings/str_format.h:362:43: note: in instantiation of template type alias 'FormatSpec' requested here
362 | [[nodiscard]] std::string StrFormat(const FormatSpec& format,
| ^
test.cc:35:13: note: while substituting deduced template arguments into function template 'StrFormat' [with Args = ]
35 | EXPECT_EQ(absl::StrFormat("%v", Point{1, 2}), "(1, 2)");
| ^
external/abseil-cpp+/absl/strings/internal/str_format/arg.h:130:6: note: candidate function [with T = Point]
130 | auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
| ^
external/abseil-cpp+/absl/strings/internal/str_format/arg.h:164:6: note: candidate function [with T = Point]
164 | auto FormatConvertImpl(const T& v, FormatConversionSpecImpl,
| ^
test.cc:35:13: error: no matching function for call to 'StrFormat'
35 | EXPECT_EQ(absl::StrFormat("%v", Point{1, 2}), "(1, 2)");
| ^~~~~~~~~~~~~~~
```

I would expect that this compiles and prefers AbslFormatConvert over AbslStringify (while StrCat and GoogleTest would ignore AbslFormatConvert).

### Steps to reproduce the problem

MODULE.bazel:

```
bazel_dep(name = "rules_cc", version = "0.2.9")
bazel_dep(name = "googletest", version = "1.17.0.bcr.1")
bazel_dep(name = "abseil-cpp", version = "20250814.1")
```

BUILD.bazel:

```
load("@rules_cc//cc:cc_test.bzl", "cc_test")

cc_test(
name = "test",
srcs = ["test.cc"],
deps = [
"@abseil-cpp//absl/strings:str_format",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)
```

test.cc:

```c++
#include

#include "absl/strings/str_format.h"
#include "gtest/gtest.h"

struct Point {
template
friend void AbslStringify(Sink& sink, const Point& p) {
absl::Format(&sink, "(%d, %d)", p.x, p.y);
}

friend absl::FormatConvertResult
AbslFormatConvert(const Point& p,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s) {
absl::Format(s, "(%d, %d)", p.x, p.y);
return {true};
}

int x;
int y;
};

TEST(CustomStringify, Works) {
EXPECT_EQ(absl::StrFormat("%v", Point{1, 2}), "(1, 2)");
}
```

.bazelrc:

```
build --define=absl=1
```

### What version of Abseil are you using?

20250814.1

### What operating system and version are you using?

macOS Tahoe

### What compiler and version are you using?

Apple clang version 17.0.0 (clang-1700.3.19.1)

### What build system are you using?

bazel 8.4.2

### Additional context

_No response_

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.