Commit 38bc3423 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[base] Add dereference operators to StrongAlias

This change adds operator-> and operator* to base::StrongAlias. These
dereference operators are customary for wrapper types like StrongAlias,
allow for more convenience and allow passing StrongAlias to generic APIs
like base::invoke.

Bug: 954080
Change-Id: I2e2e8da600f20fa9947c615cb2e016a50160d8e8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2553428Reviewed-by: default avatarŁukasz Anforowicz <lukasza@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#830532}
parent 6a86b156
...@@ -35,11 +35,14 @@ namespace base { ...@@ -35,11 +35,14 @@ namespace base {
// //
// using Orange = StrongAlias<class OrangeTag, int>; // using Orange = StrongAlias<class OrangeTag, int>;
// using Apple = StrongAlias<class AppleTag, int>; // using Apple = StrongAlias<class AppleTag, int>;
// using Banana = StrongAlias<class BananaTag, std::string>;
// Apple apple(2); // Apple apple(2);
// Banana banana("Hello");
// Orange orange = apple; // Does not compile. // Orange orange = apple; // Does not compile.
// Orange other_orange = orange; // Compiles, types match. // Orange other_orange = orange; // Compiles, types match.
// Orange x = orange + apple; // Does not compile. // Orange x = orange + apple; // Does not compile.
// Orange y = Orange(orange.value() + apple.value()); // Compiles. // Orange y = Orange(orange.value() + apple.value()); // Compiles.
// Orange z = Orange(banana->size() + *other_orange); // Compiles.
// if (orange > apple); // Does not compile. // if (orange > apple); // Does not compile.
// if (orange > other_orange); // Compiles. // if (orange > other_orange); // Compiles.
// void foo(Orange); // void foo(Orange);
...@@ -59,7 +62,8 @@ namespace base { ...@@ -59,7 +62,8 @@ namespace base {
// impossible, without reflection, to expose all methods of the UnderlyingType // impossible, without reflection, to expose all methods of the UnderlyingType
// in StrongAlias's interface. It's also potentially unwanted (ex. you don't // in StrongAlias's interface. It's also potentially unwanted (ex. you don't
// want to be able to add two StrongAliases that represent socket handles). // want to be able to add two StrongAliases that represent socket handles).
// A getter is provided in case you need to access the UnderlyingType. // A getter and dereference operators are provided in case you need to access
// the UnderlyingType.
// //
// See also // See also
// - //styleguide/c++/blink-c++.md which provides recommendation and examples of // - //styleguide/c++/blink-c++.md which provides recommendation and examples of
...@@ -76,6 +80,16 @@ class StrongAlias { ...@@ -76,6 +80,16 @@ class StrongAlias {
constexpr explicit StrongAlias(UnderlyingType&& v) noexcept constexpr explicit StrongAlias(UnderlyingType&& v) noexcept
: value_(std::move(v)) {} : value_(std::move(v)) {}
constexpr UnderlyingType* operator->() { return &value_; }
constexpr const UnderlyingType* operator->() const { return &value_; }
constexpr UnderlyingType& operator*() & { return value_; }
constexpr const UnderlyingType& operator*() const& { return value_; }
constexpr UnderlyingType&& operator*() && { return std::move(value_); }
constexpr const UnderlyingType&& operator*() const&& {
return std::move(value_);
}
constexpr UnderlyingType& value() & { return value_; } constexpr UnderlyingType& value() & { return value_; }
constexpr const UnderlyingType& value() const& { return value_; } constexpr const UnderlyingType& value() const& { return value_; }
constexpr UnderlyingType&& value() && { return std::move(value_); } constexpr UnderlyingType&& value() && { return std::move(value_); }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include "base/strings/string_piece.h"
#include "base/template_util.h" #include "base/template_util.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -114,6 +115,39 @@ TYPED_TEST(StrongAliasTest, CanBeConstructedFromMoveOnlyType) { ...@@ -114,6 +115,39 @@ TYPED_TEST(StrongAliasTest, CanBeConstructedFromMoveOnlyType) {
EXPECT_EQ(*b.value(), GetExampleValue<TypeParam>(1)); EXPECT_EQ(*b.value(), GetExampleValue<TypeParam>(1));
} }
TYPED_TEST(StrongAliasTest, MutableOperatorArrow) {
// Note, using a move-only unique_ptr to T:
using Ptr = std::unique_ptr<TypeParam>;
using FooAlias = StrongAlias<class FooTag, Ptr>;
FooAlias a(std::make_unique<TypeParam>());
EXPECT_TRUE(a.value());
// Check that `a` can be modified through the use of operator->.
a->reset();
EXPECT_FALSE(a.value());
}
TYPED_TEST(StrongAliasTest, MutableOperatorStar) {
// Note, using a move-only unique_ptr to T:
using Ptr = std::unique_ptr<TypeParam>;
using FooAlias = StrongAlias<class FooTag, Ptr>;
FooAlias a(std::make_unique<TypeParam>());
FooAlias b(std::make_unique<TypeParam>());
EXPECT_TRUE(*a);
EXPECT_TRUE(*b);
// Check that both the mutable l-value and r-value overloads work and we can
// move out of the aliases.
{ Ptr ignore(*std::move(a)); }
{ Ptr ignore(std::move(*b)); }
EXPECT_FALSE(a.value());
EXPECT_FALSE(b.value());
}
TYPED_TEST(StrongAliasTest, MutableValue) { TYPED_TEST(StrongAliasTest, MutableValue) {
// Note, using a move-only unique_ptr to T: // Note, using a move-only unique_ptr to T:
using Ptr = std::unique_ptr<TypeParam>; using Ptr = std::unique_ptr<TypeParam>;
...@@ -296,10 +330,20 @@ TYPED_TEST(StrongAliasTest, CanDifferentiateOverloads) { ...@@ -296,10 +330,20 @@ TYPED_TEST(StrongAliasTest, CanDifferentiateOverloads) {
TEST(StrongAliasTest, EnsureConstexpr) { TEST(StrongAliasTest, EnsureConstexpr) {
using FooAlias = StrongAlias<class FooTag, int>; using FooAlias = StrongAlias<class FooTag, int>;
using BarAlias = StrongAlias<class BarTag, base::StringPiece>;
// Check constructors. // Check constructors.
static constexpr FooAlias kZero{}; static constexpr FooAlias kZero{};
static constexpr FooAlias kOne(1); static constexpr FooAlias kOne(1);
static constexpr BarAlias kHello("Hello");
// Check operator->.
static_assert(kHello->size() == 5, "");
// Check operator*.
static_assert(*kZero == 0, "");
static_assert(*kOne == 1, "");
static_assert(*kHello == "Hello", "");
// Check value(). // Check value().
static_assert(kZero.value() == 0, ""); static_assert(kZero.value() == 0, "");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment