【发布时间】:2015-08-21 16:07:22
【问题描述】:
假设我有以下定义嵌套类的模板类:
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++),或者如何声明朋友,甚至如何声明模板的朋友。它询问如何为模板类的非模板嵌套成员声明朋友(如标题所述)。
试图以“正常”的方式定义特化是行不通的,因为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; };
};
};
上面的错误说明这些朋友的实际定义一定是脱节的:
template <typename T>
struct foo {
struct bar {
friend struct maybeChangeType<bar>;
};
};
但现在我们又回到了开始的地方:任何为 foo<T>::bar 定义特化的尝试都会失败,因为它在不可推导的上下文中使用了 bar。
注意:我可以通过提供友元重载内联来解决函数问题,但这对类没有帮助。
注意:我可以通过将内部类移出命名空间范围来解决此问题,但这会严重污染命名空间(许多内部类用户实际上没有任何业务可玩)并使实现复杂化(例如,他们会不再可以访问其封闭类的私有成员,friend 声明的数量将激增)。
注意:我理解为什么允许任意特化名称 foo<T>::bar 会很危险/不受欢迎(例如,如果 foo<T> 有 using bar = T 会怎样),但在这种情况下 bar 确实是一个类(甚至不是模板!) foo 确实定义了,因此不应该有任何 ODR 毛茸茸或专业化会影响其他(意外)类型的风险。
想法?
【问题讨论】:
-
既然您已经知道如何解决过载问题,您是否想将您的问题简化为专业化问题?
-
template <typename T, typename Enabler> struct maybeChangeType可能更简单... -
@Barry 好主意,完成了。
-
@Jarod42 你能详细说明一下吗?
-
@dyp 向
maybeChangeType()抛出一个参数,看起来像一个答案?
标签: c++ templates inner-classes friend template-specialization