abseil / abseil/abseil-cpp

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

Aberta
#1,966 0 comentários 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
C++
Estrelas
18.1k
Forks
3.2k
Merge médio
20h 36min
PRs com merge (30d)
1

Descrição

### 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_

Guia de contribuição

Abrir o guia de contribuição

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.