嵌套模板类的模板类模板模板的专业化

jca*_*er2 5 c++ templates template-specialization

通常,您可以针对实例化的模板类部分地专门化模板类.例如

template<class T>
struct specialize_me {};

template<class T>
struct specialize_me<std::vector<T>> {
    static const int foo = 3;
};
Run Code Online (Sandbox Code Playgroud)

模板类specialize_me部分专门针对实例化的模板类std::vector<T>.对于任何类,在specialize_me实例化时选择此特化.std::vector<T>T

int main() {
    std::cout << specialize_me<std::vector<int>>::foo; // Compiles.
}
Run Code Online (Sandbox Code Playgroud)

但是,我无法弄清楚如何针对实例化的嵌套模板类专门化模板模板类:

// Nested template class.
template<class T>
struct Either {
    template<class U>
    struct Or {};
};

template<template<class> class T>
struct specialize_me_2 {};

template<class T>
struct specialize_me_2<Either<T>::template Or> {
    static const int foo = 3;
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,当我使用任何类的类实例化时,不会选择特化.我的猜测是,这是因为编译器将不得不证实或否认,"目前存在这样相同类型的实例化",以便选择我的专业化,它没有被编程也没有规定这样做.specialize_me_2Either<T>::template OrTTEither<T>::template Orspecialize_me_2

int main() {
    std::cout << specialize_me_2<Either<int>::Or>::foo; // Does not compile.  'foo' is not a member of specialize_me_2<Either<int>::Or>.
}
Run Code Online (Sandbox Code Playgroud)

是否有一种专门化的方法,以便在任何实例化specialize_me_2specialize_me_2都选择专门化?Either<T>::OrT

这个Either结构最终将表示一个携带错误的类型,因此Either<T>表示它T是错误类型,并Either<T>::Or<U>表示这U是成功计算所携带的类型.

如果这是不可能的,我仍然可以使用#defines来使您能够根据需要定义Either<T>每个T,其中#define还包括该specialize_me_2特定的特化Either<T>::Or.实际上,我打算Either在程序中使用结构template<class T> using FooError = Either<Foo>::Or<T>,然后通过编写然后编写FooError<Bar>,FooError<Quux>等等,因此使用它不会与预期的用法有很大的差别.

max*_*x66 1

有趣的问题。

为了解决这个问题而不会太痛苦......如果你可以using在里面添加新类型Or

template <typename T>
struct Either
 {
   template <typename>
   struct Or
    { using specialOrType = T; };
 };
Run Code Online (Sandbox Code Playgroud)

然后您可以添加第二个模板参数,void默认类型名称为specialize_me_2

template <template <typename> class C, typename = void>
struct specialize_me_2
 { static const int foo = 2; };
Run Code Online (Sandbox Code Playgroud)

并使用 SFINAEspecialOrType

template <typename ...>
using myVoidT = void;

template <template <typename> class C>
struct specialize_me_2<C, myVoidT<typename C<void>::specialOrType>>
 {
   using T = typename C<void>::specialOrType;

   static const int foo = 3;
 };
Run Code Online (Sandbox Code Playgroud)

你得到你的工作专业。

从 C++17开始myVoidT,您显然可以使用std::void_t.

请注意,这样您无法推断出原始T类型,但可以通过 恢复它specialOrType

还要观察到这个要求(如 aschepler 所指出的)Or<void>是一个有效的专业化。如果不是这种情况,您应该选择另一种类型X,这样它Or<X>对于所有Either<T>. 举例来说,假设Or<int>是 每个 的有效专业化Either<T>,该专业化变为

template <template <typename> class C>
struct specialize_me_2<C, myVoidT<typename C<int>::specialOrType>>
 {
   using T = typename C<int>::specialOrType;

   static const int foo = 3;
 };
Run Code Online (Sandbox Code Playgroud)

以下是一个完整的工作示例

#include <iostream>

template <typename ...>
using myVoidT = void;

template <typename>
struct NoEither
 { };

template <typename T>
struct Either
 {
   template <typename>
   struct Or
    { using specialOrType = T; };
 };

template <template <typename> class C, typename = void>
struct specialize_me_2
 { static const int foo = 2; };

template <template <typename> class C>
struct specialize_me_2<C, myVoidT<typename C<void>::specialOrType>>
 {
   using T = typename C<void>::specialOrType;

   static const int foo = 3;
 };

int main ()
 {
    std::cout << specialize_me_2<NoEither>::foo << std::endl;
    std::cout << specialize_me_2<Either<int>::template Or>::foo << std::endl;
 }
Run Code Online (Sandbox Code Playgroud)