Rya*_*yan 8 c++ templates friend inner-classes template-specialization
假设我有以下模板类来定义嵌套类:
template <typename T>
struct foo {
struct bar { };
};
Run Code Online (Sandbox Code Playgroud)
假设我编写的环境也有以下帮助器类,它应该专门用于需要特殊处理的任何类型:
template <typename T>
struct maybeChangeType { using type = T; } /* default: same type */
Run Code Online (Sandbox Code Playgroud)
我怎么能专门maybeChangeType为foo<T>::bar?比如说,它很容易专门用于,foo<int>::bar但foo将会使用100多个不同的,T所以这不是一个真正的选择.
注意:在将此问题标记为重复之前,请仔细阅读.这个问题并不是要问如何专注于一般(例如,在c ++中理解模板),或如何声明朋友,甚至如何声明模板的朋友.它询问如何为模板类的非模板嵌套成员声明朋友(如标题所述).
尝试以"正常"方式定义专业化不起作用,因为foo<T>::bar它不是可推导的上下文(坏符号:它需要typename在前面):
/* error: template parameters not deducible in partial specialization */
template <typename T>
struct maybeChangeType<typename foo<T>::bar>;
Run Code Online (Sandbox Code Playgroud)
将专业化声明为朋友也会产生编译错误:
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; };
};
};
Run Code Online (Sandbox Code Playgroud)
上述错误清楚地表明这些朋友的实际定义必须脱节:
template <typename T>
struct foo {
struct bar {
friend struct maybeChangeType<bar>;
};
};
Run Code Online (Sandbox Code Playgroud)
但现在我们又回到了我们开始的地方:任何定义专业化的尝试foo<T>::bar都将失败,因为它bar在非可推导的上下文中使用.
注意:我可以通过提供朋友重载内联来解决函数问题,但这对于类没有帮助.
注意:我可以通过将内部类移到命名空间范围来解决这个问题,但这会显着污染命名空间(用户真正没有业务的许多内部类)并使实现复杂化(例如,他们将不再拥有访问其封闭类的私有成员和friend声明的数量将激增).
注:我明白为什么它会是危险的/不希望让这个名字任意专业化foo<T>::bar(如果有什么foo<T>有using bar = T例如),但在这种情况下,bar确实是一个类(甚至不是一个模板!)其中foo的确实定义,所以不该不存在任何ODR毛羽或专业化会影响其他(非预期)类型的风险.
想法?
如果您可以导出T中的模板参数bar,并且可以向 中添加另一个(默认)模板参数maybeChangeType,则可以尝试以下操作:
#include <type_traits>
template <typename T>
struct foo {
struct bar {
using type = T;
};
};
template <typename T, typename = void>
struct maybeChangeType { using type = T; }; /* default: same type */
template <typename T>
struct maybeChangeType<T,
typename std::enable_if<std::is_same<T,
typename foo<typename T::type>::bar
>::value
>::type>
{ using type = T; };
int main() {}
Run Code Online (Sandbox Code Playgroud)