class 模板成员的特化 class
specialization of class member of a template class
设 A
为包含内部 struct
的模板 class。我想根据 A
的模板参数专门化内部结构(并且仅此)。以下代码似乎可以正确完成这项工作:
#include <iostream>
template <bool rgb>
struct A {
struct colors;
A();
};
template <>
struct A<true>::colors { enum : std::size_t { red, green, blue }; };
template <>
struct A<false>::colors { enum : std::size_t { cyan, magenta, yellow, black }; };
template<bool rgb>
A<rgb>::A()
{
if (rgb) {
std::cout << "rgb true" << std::endl;
}
else {
std::cout << "rgb false" << std::endl;
}
}
int main()
{
using colors_true = A<true>::colors;
using colors_false = A<false>::colors;
A<true> at{};
A<false> af{};
std::cout << colors_true::red << std::endl;
std::cout << colors_false::yellow << std::endl;
}
看到了live on Coliru.
(A
的构造函数只是说明我只专A::colors
)
现在,考虑 A
包含附加模板参数的情况。我想模仿上面的代码,只专注于 bool
参数。但是,以下代码无法编译:
#include <iostream>
template <bool rgb, int i>
struct A {
struct colors;
A();
};
template <int i>
struct A<true, i>::colors { enum : std::size_t { red, green, blue }; };
template <int i>
struct A<false, i>::colors { enum : std::size_t { cyan, magenta, yellow, black }; };
template<bool rgb, int i>
A<rgb, i>::A()
{
if (rgb) {
std::cout << "rgb true";
}
else {
std::cout << "rgb false";
}
std::cout << " i = " << i << std::endl;
}
int main()
{
using colors_true = A<true, 2>::colors;
using colors_false = A<false, 5>::colors;
A<true, 2> at{};
A<false, 5> af{};
std::cout << colors_true::red << std::endl;
std::cout << colors_false::yellow << std::endl;
}
看到了live on Coliru.
编译错误为:
main.cpp:10:20: error: invalid class name in declaration of 'class A<true, i>::colors'
10 | struct A<true, i>::colors { enum : std::size_t { red, green, blue }; };
| ^~~~~~
main.cpp:13:21: error: invalid class name in declaration of 'class A<false, i>::colors'
13 | struct A<false, i>::colors { enum : std::size_t { cyan, magenta, yellow, black }; };
| ^~~~~~
A
的部分特化,如以下代码
#include <iostream>
template <bool rgb, int i>
struct A {
struct colors;
A();
};
template <int i>
struct A<true, i> {
struct colors { enum : std::size_t { red, green, blue }; };
};
template <int i>
struct A<false, i> {
struct colors { enum : std::size_t { cyan, magenta, yellow, black }; };
};
template<bool rgb, int i>
A<rgb, i>::A()
{
if (rgb) {
std::cout << "rgb true";
}
else {
std::cout << "rgb false";
}
std::cout << " i = " << i << std::endl;
}
int main()
{
using colors_true = A<true, 2>::colors;
using colors_false = A<false, 5>::colors;
A<true, 2> at{};
A<false, 5> af{};
std::cout << colors_true::red << std::endl;
std::cout << colors_false::yellow << std::endl;
}
也不行。看到它live on Coliru。当代码编译时,A
的部分特化完全掩盖了构造函数 A::A()
,如输出所示。换句话说,在上面的代码中,编译器选择了 A
的两个部分专用版本,其中构造函数未明确定义。
作为一种解决方法,我发现可以使用继承:
#include <iostream>
template <bool rgb>
struct colors_type;
template <>
struct colors_type<true> {
struct colors { enum : std::size_t { red, green, blue }; };
};
template <>
struct colors_type<false> {
struct colors { enum : std::size_t { cyan, magenta, yellow, black }; };
};
template <bool rgb, int i>
struct A : public colors_type<rgb> {
A();
};
template<bool rgb, int i>
A<rgb, i>::A()
{
if (rgb) {
std::cout << "rgb true";
}
else {
std::cout << "rgb false";
}
std::cout << " i = " << i << std::endl;
}
int main()
{
using colors_true = A<true, 2>::colors;
using colors_false = A<false, 5>::colors;
A<true, 2> at{};
A<false, 5> af{};
std::cout << colors_true::red << std::endl;
std::cout << colors_false::yellow << std::endl;
}
看到了live on Coliru.
为什么只有当我完全特化封闭 class 的模板参数(第一个代码)时我才能特化内部结构,而不是当我只部分特化它们时(第二个代码) ?
除了继承技巧(第四代码)之外,还有其他解决问题的可能性吗?
这是指定语言的方式:
您可以显式特化 class 模板的成员 class(参见 [temp.expl.spec])
您可以为 class 提供部分专业化(参见 [temp.class.spec])
对[temp.class.spec]感兴趣:
A partial specialization of a class template provides an alternative definition of the template that is used instead of the primary definition
Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization
我认为您提供的继承技巧是最好的技巧,或者至少是最常用的技巧。
正如 Oliv 的回答所解释的,该语言不允许嵌套 class.
的部分专业化
在这种情况下,您还可以通过使内部 class 成为类型别名而不继承来获得您想要的结果:
template <bool rgb>
struct colors_type;
template <>
struct colors_type<true> {
enum : std::size_t { red, green, blue };
};
template <>
struct colors_type<false> {
enum : std::size_t { cyan, magenta, yellow, black };
};
template <bool rgb, int i>
struct A {
using colors = colors_type<rgb>;
A();
};
对于此示例,这两种解决方案没有太多明显的优点或缺点,但在一些更复杂的情况下,其中一种可能是更简单或更清晰的途径。 (虽然我猜想继承在这些更一般的用例中更有用。)
设 A
为包含内部 struct
的模板 class。我想根据 A
的模板参数专门化内部结构(并且仅此)。以下代码似乎可以正确完成这项工作:
#include <iostream>
template <bool rgb>
struct A {
struct colors;
A();
};
template <>
struct A<true>::colors { enum : std::size_t { red, green, blue }; };
template <>
struct A<false>::colors { enum : std::size_t { cyan, magenta, yellow, black }; };
template<bool rgb>
A<rgb>::A()
{
if (rgb) {
std::cout << "rgb true" << std::endl;
}
else {
std::cout << "rgb false" << std::endl;
}
}
int main()
{
using colors_true = A<true>::colors;
using colors_false = A<false>::colors;
A<true> at{};
A<false> af{};
std::cout << colors_true::red << std::endl;
std::cout << colors_false::yellow << std::endl;
}
看到了live on Coliru.
(A
的构造函数只是说明我只专A::colors
)
现在,考虑 A
包含附加模板参数的情况。我想模仿上面的代码,只专注于 bool
参数。但是,以下代码无法编译:
#include <iostream>
template <bool rgb, int i>
struct A {
struct colors;
A();
};
template <int i>
struct A<true, i>::colors { enum : std::size_t { red, green, blue }; };
template <int i>
struct A<false, i>::colors { enum : std::size_t { cyan, magenta, yellow, black }; };
template<bool rgb, int i>
A<rgb, i>::A()
{
if (rgb) {
std::cout << "rgb true";
}
else {
std::cout << "rgb false";
}
std::cout << " i = " << i << std::endl;
}
int main()
{
using colors_true = A<true, 2>::colors;
using colors_false = A<false, 5>::colors;
A<true, 2> at{};
A<false, 5> af{};
std::cout << colors_true::red << std::endl;
std::cout << colors_false::yellow << std::endl;
}
看到了live on Coliru.
编译错误为:
main.cpp:10:20: error: invalid class name in declaration of 'class A<true, i>::colors'
10 | struct A<true, i>::colors { enum : std::size_t { red, green, blue }; };
| ^~~~~~
main.cpp:13:21: error: invalid class name in declaration of 'class A<false, i>::colors'
13 | struct A<false, i>::colors { enum : std::size_t { cyan, magenta, yellow, black }; };
| ^~~~~~
A
的部分特化,如以下代码
#include <iostream>
template <bool rgb, int i>
struct A {
struct colors;
A();
};
template <int i>
struct A<true, i> {
struct colors { enum : std::size_t { red, green, blue }; };
};
template <int i>
struct A<false, i> {
struct colors { enum : std::size_t { cyan, magenta, yellow, black }; };
};
template<bool rgb, int i>
A<rgb, i>::A()
{
if (rgb) {
std::cout << "rgb true";
}
else {
std::cout << "rgb false";
}
std::cout << " i = " << i << std::endl;
}
int main()
{
using colors_true = A<true, 2>::colors;
using colors_false = A<false, 5>::colors;
A<true, 2> at{};
A<false, 5> af{};
std::cout << colors_true::red << std::endl;
std::cout << colors_false::yellow << std::endl;
}
也不行。看到它live on Coliru。当代码编译时,A
的部分特化完全掩盖了构造函数 A::A()
,如输出所示。换句话说,在上面的代码中,编译器选择了 A
的两个部分专用版本,其中构造函数未明确定义。
作为一种解决方法,我发现可以使用继承:
#include <iostream>
template <bool rgb>
struct colors_type;
template <>
struct colors_type<true> {
struct colors { enum : std::size_t { red, green, blue }; };
};
template <>
struct colors_type<false> {
struct colors { enum : std::size_t { cyan, magenta, yellow, black }; };
};
template <bool rgb, int i>
struct A : public colors_type<rgb> {
A();
};
template<bool rgb, int i>
A<rgb, i>::A()
{
if (rgb) {
std::cout << "rgb true";
}
else {
std::cout << "rgb false";
}
std::cout << " i = " << i << std::endl;
}
int main()
{
using colors_true = A<true, 2>::colors;
using colors_false = A<false, 5>::colors;
A<true, 2> at{};
A<false, 5> af{};
std::cout << colors_true::red << std::endl;
std::cout << colors_false::yellow << std::endl;
}
看到了live on Coliru.
为什么只有当我完全特化封闭 class 的模板参数(第一个代码)时我才能特化内部结构,而不是当我只部分特化它们时(第二个代码) ?
除了继承技巧(第四代码)之外,还有其他解决问题的可能性吗?
这是指定语言的方式:
您可以显式特化 class 模板的成员 class(参见 [temp.expl.spec])
您可以为 class 提供部分专业化(参见 [temp.class.spec])
对[temp.class.spec]感兴趣:
A partial specialization of a class template provides an alternative definition of the template that is used instead of the primary definition
Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization
我认为您提供的继承技巧是最好的技巧,或者至少是最常用的技巧。
正如 Oliv 的回答所解释的,该语言不允许嵌套 class.
的部分专业化在这种情况下,您还可以通过使内部 class 成为类型别名而不继承来获得您想要的结果:
template <bool rgb>
struct colors_type;
template <>
struct colors_type<true> {
enum : std::size_t { red, green, blue };
};
template <>
struct colors_type<false> {
enum : std::size_t { cyan, magenta, yellow, black };
};
template <bool rgb, int i>
struct A {
using colors = colors_type<rgb>;
A();
};
对于此示例,这两种解决方案没有太多明显的优点或缺点,但在一些更复杂的情况下,其中一种可能是更简单或更清晰的途径。 (虽然我猜想继承在这些更一般的用例中更有用。)