gpt4 book ai didi

c++ - 如何为模板类中定义的类定义 friend

转载 作者:可可西里 更新时间:2023-11-01 17:56:44 25 4
gpt4 key购买 nike

假设我有以下定义嵌套类的模板类:

template <typename T>
struct foo {
struct bar { };
};

假设我正在编写代码的环境也有以下帮助程序类,它应该专门用于需要特殊处理的任何类型:

template <typename T>
struct maybeChangeType { using type = T; } /* default: same type */

我怎样才能专攻maybeChangeType对于 foo<T>::bar ?专门针对 foo<int>::bar 很容易,但是 foo将与 100 多种不同的 T 一起使用所以这不是一个真正的选择。

注意:请在将此问题标记为重复之前仔细阅读。这个问题不是询问一般如何专门化(例如 Understanding templates in c++ ),或者如何声明 friend ,甚至如何声明模板的 friend 。它询问如何为模板类的非模板嵌套成员声明友元(如标题所述)。

尝试以“正常”方式定义特化是行不通的,因为 foo<T>::bar不是可推导的上下文(不好的迹象:它需要在前面 typename):

/* error: template parameters not deducible in partial specialization */
template <typename T>
struct maybeChangeType<typename foo<T>::bar>;

将特化声明为友元也会产生编译错误:

template <typename T>
struct foo {
struct bar {
/* errors:
* - class specialization must appear at namespace scope
* - class definition may not be declared a friend
*/
template <>
friend struct maybeChangeType<bar> { using type=T; };
};
};

以上错误清楚地表明这些 friend 的实际定义必须出线:

template <typename T>
struct foo {
struct bar {
friend struct maybeChangeType<bar>;
};
};

但现在我们回到了起点:任何为 foo<T>::bar 定义特化的尝试将失败,因为它使用 bar在不可推导的上下文中。

注意:我可以通过提供内联友元重载来解决函数的问题,但这对类没有帮助。

注意:我可以通过将内部类移出命名空间范围来解决这个问题,但这会严重污染命名空间(很多内部类用户实际上没有业务可玩)并使实现复杂化(例如,他们会不再能够访问其封闭类的私有(private)成员,并且 friend 声明的数量会激增)。

注意:我理解为什么允许任意特化名称 foo<T>::bar 是危险的/不可取的(如果 foo<T>using bar = T 会怎么样),但在这种情况下 bar实际上是 foo 确实定义的类(甚至不是模板!),因此不应该有任何 ODR 毛羽或特化会影响其他(非预期​​)类型的风险。

想法?

最佳答案

作为一种侵入式解决方案,可以使用函数进行类型编程(元编程)。您可以将类型函数编写为友元函数:

template<typename T> struct type_t { using type = T; };

template <typename T>
struct foo {
struct bar {
friend constexpr auto maybeChangeType_adl(type_t<bar>) -> type_t<T>
{ return {}; }
};
};

替换type_t<T>与任何 type_t<my_type_function_result> .定义此函数不是必需的,但有时很方便,例如用于常量表达式中的计算。 type_t可以使用比较运算符进行增强,以替换 std::is_same<A, B>带中缀 a == b例如。类型type_t<T>使用而不是 T直接有两个原因:

  1. 对于 maybeChangeType_adl 的定义, 有必要构造一个返回类型的对象。
  2. 并非所有类型都可以从函数返回。例如。抽象类型、函数类型、数组类型。那些仍然可以用作模板参数。

在 C++14 中,我会使用变量模板来实现这个功能:

template<typename T> constexpr auto type = type_t<T>{};

// ...

friend constexpr auto maybeChangeType_adl(type_t<bar>) { return type<T>; };

虽然这失去了一些对称性(参数与返回类型)。


无论哪种情况,都可以查询类型如下:

template<typename T> using inner_type = typename T::type;

template<typename T> using maybeChangeType =
inner_type<decltype(maybeChangeType_adl(type_t<T>{}))>;

回退函数 maybeChangeType可以提供镜像 OP 中的主模板:

template<typename T> auto maybeChangeType(type_t<T>) -> type_t<T> { return {}; }

或者,您专攻 maybeChangeType maybeChangeType_adl 存在的类模板功能:

template<typename T, typename = void>
struct maybeChangeType { using type = T; };

template<typename T>
struct maybeChangeType<T, void_t<decltype(maybeChangeType_adl(type_t<T>{}))>>
{ using type = inner_type<decltype(maybeChangeType_adl(type_t<T>{}))>; };

关于c++ - 如何为模板类中定义的类定义 friend ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32144877/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com