c++ - 嵌套模板类的模板类模板参数特化

标签 c++ templates template-specialization

通常您可以针对实例化的模板类部分特化模板类。例如

template<class T>
struct specialize_me {};

template<class T>
struct specialize_me<std::vector<T>> {
    static const int foo = 3;
};

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

int main() {
    std::cout << specialize_me<std::vector<int>>::foo; // Compiles.
}

但是,我不知道如何针对实例化的嵌套模板类专门化模板模板类:

// 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;
};

在这种情况下,当我实例化 specialize_me_2 时,选择特化同类Either<T>::template Or对于任何类(class) T .我的猜测是,发生这种情况是因为编译器必须确认或拒绝“存在一个 T,使得 Either<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>.
}

有没有办法专门化specialize_me_2这样每当 specialize_me_2 时都会选择特化用 Either<T>::Or 实例化对于任何 T

Either struct 最终将表示一个错误携带类型,所以 Either<T>表示T是错误类型,Either<T>::Or<U>表示U是成功计算携带的类型。

如果这是不可能的,我可能仍然可以使用 #define s 使您能够定义 Either<T>对于每个 T根据需要,#define还包括 specialize_me_2特定的特化 Either<T>::Or .事实上,我打算使用 Either通过编写在程序中构造 template<class T> using FooError = Either<Foo>::Or<T>无论如何然后写FooError<Bar> , FooError<Quux>等等,所以使用它不会对预期用途有很大的影响。

最佳答案

有趣的问题。

要轻松解决它...如果您可以添加新的 using在里面输入 Or

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

然后你可以添加第二个模板参数,一个带有void的类型名默认情况下,在 specialize_me_2

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

并在 specialOrType 上使用 SFINAE

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;
 };

您获得工作特化。

而不是 myVoidT , 从 C++17 开始,你显然可以使用 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;
 };

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

#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;
 }

关于c++ - 嵌套模板类的模板类模板参数特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50894987/

相关文章:

c++ - 字符串**数组;数组 [行] [列] = "string"上的段错误; C++

C++ 编译时间特定函数与可变参数模板

c++ - C++ 模板中的特殊情况

c++ - 模板类特化

C++ 模板类,根据类型名改变类方法的行为

c++ - XML 解析 : Checking for strings within string C++

c++ - 需要帮助解决我程序中的小问题

c++ - 从容器中提取指针的语法 back()

C++ 可变模板参数和元组迭代

c++ - "Undefined reference to"模板类构造函数