abseil / abseil/abseil-cpp

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

Đang mở
#1,966 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
C++
Star
18.1k
Fork
3.2k
Merge trung bình
20 giờ 36 phút
Pull request đã merge (30 ngày)
1

Mô tả

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

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.