Date: Sat, 7 Dec 2019 12:59:41 -0600
Hi all,
Consider the following struct
struct B {
Foo foo() const noexcept;
Bar bar() const;
};
Now I have a class A that uses B and then wants to expose interface from B.
=======
Option 1
=======
A common way to do this would be:
class A {
public:
auto foo() const { return b_.foo(); }
auto bar() const noexcept { return b_.bar(); } // Oops--Shouldn’t be noexcept!
private:
B b_;
};
=======
Option 2
=======
Another possibility (which I usually discourage due to encapsulation issues) would be:
class A : public B {};
=======
Option 3
=======
Or, another option would be to do something like:
class A : private B {
public:
using B::foo;
using B::bar;
};
which is awkward in terms of encapsulation, but at least is explicit in terms of the exposed interface.
I would like to consider expanding the use cases where in-class using declarations can be used. What if instead of Option 1 we had:
=======
Option 4
=======
class A {
public:
using B::foo; // implicitly noexcept, introduces foo() function bound to b_
using B::bar; // not noexcept, introduces bar() function bound to b_
private:
B b_;
};
This option allows exposing interface by contained types as interface of the containing type, without introducing possibilities for mismatched qualification (noexcept vs. not). For cases where multiple data members of the same type are used, one could imagine a syntax like:
class A {
public:
using B::foo(b1_); // implicitly noexcept, introduces foo() function bound to b1_
using B::bar(b1_); // not noexcept, introduces bar() function bound to b1_
using bar2 = B::bar(b2_); // introduces ‘bar2’ function that is bar() bound to b2_
private:
B b1_;
B b2_;
};
I suspect introducing an alias (i.e. bar2) would cause parsing problems, but wanted to throw it out there.
Interested in your thoughts. And thanks!
Kyle Knoepfel
Consider the following struct
struct B {
Foo foo() const noexcept;
Bar bar() const;
};
Now I have a class A that uses B and then wants to expose interface from B.
=======
Option 1
=======
A common way to do this would be:
class A {
public:
auto foo() const { return b_.foo(); }
auto bar() const noexcept { return b_.bar(); } // Oops--Shouldn’t be noexcept!
private:
B b_;
};
=======
Option 2
=======
Another possibility (which I usually discourage due to encapsulation issues) would be:
class A : public B {};
=======
Option 3
=======
Or, another option would be to do something like:
class A : private B {
public:
using B::foo;
using B::bar;
};
which is awkward in terms of encapsulation, but at least is explicit in terms of the exposed interface.
I would like to consider expanding the use cases where in-class using declarations can be used. What if instead of Option 1 we had:
=======
Option 4
=======
class A {
public:
using B::foo; // implicitly noexcept, introduces foo() function bound to b_
using B::bar; // not noexcept, introduces bar() function bound to b_
private:
B b_;
};
This option allows exposing interface by contained types as interface of the containing type, without introducing possibilities for mismatched qualification (noexcept vs. not). For cases where multiple data members of the same type are used, one could imagine a syntax like:
class A {
public:
using B::foo(b1_); // implicitly noexcept, introduces foo() function bound to b1_
using B::bar(b1_); // not noexcept, introduces bar() function bound to b1_
using bar2 = B::bar(b2_); // introduces ‘bar2’ function that is bar() bound to b2_
private:
B b1_;
B b2_;
};
I suspect introducing an alias (i.e. bar2) would cause parsing problems, but wanted to throw it out there.
Interested in your thoughts. And thanks!
Kyle Knoepfel
Received on 2019-12-07 13:02:20