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.

这是指定语言的方式:

对[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();
};

对于此示例,这两种解决方案没有太多明显的优点或缺点,但在一些更复杂的情况下,其中一种可能是更简单或更清晰的途径。 (虽然我猜想继承在这些更一般的用例中更有用。)