Skip to content

Commit 79549fe

Browse files
Abseil Teamcopybara-github
authored andcommitted
Add lifetimebound to absl::implicit_cast and make it work for rvalue references as it already does with lvalue references
PiperOrigin-RevId: 817776717 Change-Id: I9b01d04c05b73ff21462fbe42d5e9fc0e677a971
1 parent 6ae6cc6 commit 79549fe

File tree

4 files changed

+105
-1
lines changed

4 files changed

+105
-1
lines changed

absl/base/BUILD.bazel

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,22 @@ cc_test(
602602
],
603603
)
604604

605+
cc_test(
606+
name = "casts_test",
607+
size = "small",
608+
srcs = [
609+
"casts_test.cc",
610+
],
611+
copts = ABSL_TEST_COPTS,
612+
linkopts = ABSL_DEFAULT_LINKOPTS,
613+
deps = [
614+
":base",
615+
":core_headers",
616+
"@googletest//:gtest",
617+
"@googletest//:gtest_main",
618+
],
619+
)
620+
605621
cc_test(
606622
name = "no_destructor_test",
607623
srcs = ["no_destructor_test.cc"],

absl/base/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,19 @@ absl_cc_test(
417417
GTest::gtest_main
418418
)
419419

420+
absl_cc_test(
421+
NAME
422+
casts_test
423+
SRCS
424+
"casts_test.cc"
425+
COPTS
426+
${ABSL_TEST_COPTS}
427+
DEPS
428+
absl::base
429+
absl::core_headers
430+
GTest::gtest_main
431+
)
432+
420433
absl_cc_test(
421434
NAME
422435
errno_saver_test

absl/base/casts.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <bit> // For std::bit_cast.
3434
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
3535

36+
#include "absl/base/attributes.h"
3637
#include "absl/base/macros.h"
3738
#include "absl/meta/type_traits.h"
3839

@@ -89,9 +90,26 @@ ABSL_NAMESPACE_BEGIN
8990
//
9091
// Such implicit cast chaining may be useful within template logic.
9192
template <typename To>
92-
constexpr To implicit_cast(typename absl::type_identity_t<To> to) {
93+
constexpr std::enable_if_t<
94+
!type_traits_internal::IsView<std::enable_if_t<
95+
!std::is_reference_v<To>, std::remove_cv_t<To>>>::value,
96+
To>
97+
implicit_cast(absl::type_identity_t<To> to) {
9398
return to;
9499
}
100+
template <typename To>
101+
constexpr std::enable_if_t<
102+
type_traits_internal::IsView<std::enable_if_t<!std::is_reference_v<To>,
103+
std::remove_cv_t<To>>>::value,
104+
To>
105+
implicit_cast(absl::type_identity_t<To> to ABSL_ATTRIBUTE_LIFETIME_BOUND) {
106+
return to;
107+
}
108+
template <typename To>
109+
constexpr std::enable_if_t<std::is_reference_v<To>, To> implicit_cast(
110+
absl::type_identity_t<To> to ABSL_ATTRIBUTE_LIFETIME_BOUND) {
111+
return std::forward<absl::type_identity_t<To>>(to);
112+
}
95113

96114
// bit_cast()
97115
//

absl/base/casts_test.cc

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2025 The Abseil Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "absl/base/casts.h"
16+
17+
#include <type_traits>
18+
#include <utility>
19+
20+
#include "gtest/gtest.h"
21+
22+
namespace {
23+
24+
struct Base {
25+
explicit Base(int value) : x(value) {}
26+
Base(const Base& other) = delete;
27+
Base& operator=(const Base& other) = delete;
28+
int x;
29+
};
30+
struct Derived : Base {
31+
explicit Derived(int value) : Base(value) {}
32+
};
33+
34+
static_assert(
35+
std::is_same_v<
36+
decltype(absl::implicit_cast<Base&>(std::declval<Derived&>())), Base&>);
37+
static_assert(std::is_same_v<decltype(absl::implicit_cast<const Base&>(
38+
std::declval<Derived>())),
39+
const Base&>);
40+
41+
TEST(ImplicitCastTest, LValueReference) {
42+
Derived derived(5);
43+
EXPECT_EQ(&absl::implicit_cast<Base&>(derived), &derived);
44+
EXPECT_EQ(&absl::implicit_cast<const Base&>(derived), &derived);
45+
}
46+
47+
TEST(ImplicitCastTest, RValueReference) {
48+
Derived derived(5);
49+
Base&& base = absl::implicit_cast<Base&&>(std::move(derived));
50+
EXPECT_EQ(&base, &derived);
51+
52+
const Derived cderived(6);
53+
const Base&& cbase = absl::implicit_cast<const Base&&>(std::move(cderived));
54+
EXPECT_EQ(&cbase, &cderived);
55+
}
56+
57+
} // namespace

0 commit comments

Comments
 (0)