如何将外部类的受保护成员引用为类模板的构造函数的默认参数

How to refer to protected members of an external class as default arguments for a constructor of a class template

提问人:ardnew 提问时间:7/31/2023 最后编辑:ardnew 更新时间:7/31/2023 访问量:59

问:

如果在其他地方被问到这个问题,请原谅我(并提供链接!我找不到一个完全重复的。

不确定我是否正确地表达了 Q。

举个最小的例子:

#include <cstdint>
#include <vector>

class Priv {
protected:
    // All members of Priv are protected and should not be accessed directly.
    using Typ = uint16_t;
    //   (In reality, Typ is defined based on various macro definitions.)
    // ...
    // However, I would like to give access to classes I specifically befriend.
    // All instantiations of Public should be permitted, regardless of T.
    template <typename T> friend struct Public;
};

// Default arguments in class Public's template parameter list should be able to 
// access protected members of Priv because Public has been friend-zone'd, right?
template <typename T = Priv::Typ>
struct Public: std::vector<T> {
    inline Public(): std::vector<T>() {}
};

int main() {
        Public pub; // should default to Public<Priv::Typ>
}

但不幸的是,我似乎错误地宣布了这位朋友:

<source>:17:30: error: 'using Typ = uint16_t' is protected within this context
   17 | template <typename T = Priv::Typ>
      |  

有人可以指出我的错误吗?

C++ 模板 access-modifiers default-parameters

评论

0赞 paddy 7/31/2023
既然你显然在控制之中,那么声明为公开有什么问题呢?PrivTyp
1赞 Jesper Juhl 7/31/2023
添加一个方法来访问或只是让它...或者,也许这个问题还有更多你没有告诉我们的......publicTyppublic
1赞 user17732522 7/31/2023
默认模板参数在类作用域之外,而不是在类作用域内。它等价于在用户上下文中使用参数的位置,而不是类。因此,在此上下文中不应使用成员。从概念上讲,成员受到保护但仍然只能用作隐式默认参数的原因是什么?Public<>Public<Priv::Typ>protected
2赞 Sam Varshavchik 7/31/2023
这与模板无关。从非模板类继承的类似尝试也会出现相同的基本问题。
0赞 273K 7/31/2023
你的标题是关于私有成员的,代码是关于受保护的成员的。

答:

1赞 user17732522 7/31/2023 #1

默认模板参数在类作用域之外,而不是在类作用域内。它等价于在用户上下文中使用参数的位置,而不是类。因此,在此上下文中不应使用成员。Public<>Public<Priv::Typ>protected

您只能在 的作用域使用类的 / 成员。因此,如果您希望类模板的用户能够隐式或显式指定类型,同时仍然标记 ,那么您需要以某种方式在类范围内进行转换。例如:privateprotectedfriendTypprotectedTyp

struct PrivTypProxy;

template <typename T = PrivTypProxy>
struct Public:
    std::vector<
        std::conditional_t<
            std::is_same_v<T, PrivTypProxy>,
            Priv::Typ,
            T
         >
      >
{
    using U = std::conditional_t<
                  std::is_same_v<T, PrivTypProxy>,
                  Priv::Typ,
                  T
               >;
    inline Public(): std::vector<U>() {}
};

但我不清楚这样做的目的是什么。

评论

0赞 ardnew 7/31/2023
你说因为受到保护。但是,如果不授予对单个类的访问权,那么这些类又有什么意义呢(由于、等)呢?So it shouldn't be possible to use a protected member in this context.TypFriendprotectedpritvate
1赞 Ted Lyngmo 7/31/2023
@ardnew 关键是,它不是尝试访问 的实例,而是外部用户尝试使用 .Public<Priv::Typ>PublicPriv::TypPublicPriv::Typ
0赞 user17732522 7/31/2023
@ardnew 默认模板参数不属于任何类。它仅用于形成模板用户对的类模板专用化(然后它本身就是一个好友的类)。
1赞 user17732522 7/31/2023
@ardnew 知道或不知道什么类型的别名与是否应该允许用户使用别名完全正交的问题。您似乎希望允许用户显式命名别名,但仍然通过模板参数推导隐式命名它。我不清楚为什么需要限制显式使用。Priv::Typ
1赞 Ted Lyngmo 7/31/2023
@ardnew我认为在不改变设计的情况下,你无能为力。你问你的错误是什么,并得到了答案。我只会接受答案并重新考虑设计。