简体   繁体   English

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

[英]specialization of template template paremeter of template class for nested template class

Normally you can partially specialize a template class against an instantiated template class. 通常,您可以针对实例化的模板类部分地专门化模板类。 For instance 例如

template<class T>
struct specialize_me {};

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

the template class specialize_me is partially specialized against the instantiated template class std::vector<T> . 模板类specialize_me部分专门针对实例化的模板类std::vector<T> This specialization is selected when specialize_me is instantiated with std::vector<T> , for any class T . 当选择这种专业化specialize_me与实例化std::vector<T>对于任何类T

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

However, I cannot figure out how to specialize a template template class against an instantiated nested template class: 但是,我无法弄清楚如何针对实例化的嵌套模板类专门化模板模板类:

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

In this case, the specialization is not selected when I instantiate specialize_me_2 with the class Either<T>::template Or for any class T . 在这种情况下,当我使用类Either<T>::template Or任何类T实例化specialize_me_2时, 不会选择特化。 My guess is that this happens because the compiler would have to confirm or deny, "There exists a T such that Either<T>::template Or is the same type as the specialize_me_2 instantiation" in order to select my specialization, and it is not programmed nor specified to do so. 我的猜测是,这是因为编译器必须确认或否认,“存在一个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>.
}

Is there a way to specialize specialize_me_2 such that the specialization is selected whenever specialize_me_2 is instantiated with Either<T>::Or for any T ? 有没有办法专门化specialize_me_2这样只要specialize_me_2使用Either<T>::Or任何T实例化,就会选择特化?

This Either struct is eventually going to represent an error-carrying type, so Either<T> denotes that T is the error type, and Either<T>::Or<U> denotes that U is the type being carried by the successful computation. 这个Either结构最终将表示一个携带错误的类型,因此, Either<T>表示T是错误类型,并且Either<T>::Or<U>表示U是成功计算所携带的类型。

If this is impossible, I might still be able to use #define s to enable you to define Either<T> for each T as it is needed, where #define also includes the specialize_me_2 specialization for that particular Either<T>::Or . 如果这是不可能的,我可能仍然可以使用#define来使你能够为每个T定义Either<T> ,其中#define还包括specialize_me_2特殊化的特定Either<T>::Or Indeed, I intend to use the Either struct in programs by writing template<class T> using FooError = Either<Foo>::Or<T> anyway and then write FooError<Bar> , FooError<Quux> and so on, so using this wouldn't be a huge break from the intended usage. 实际上,我打算通过template<class T> using FooError = Either<Foo>::Or<T>编写template<class T> using FooError = Either<Foo>::Or<T>程序中的Either结构,然后编写FooError<Bar>FooError<Quux>等等,所以使用这不会是预期用途的巨大突破。

Intriguing problem. 有趣的问题。

To solve it without too much pain... if you can add new using type inside Or 要解决它而不要太痛苦...如果你可以在Or里面添加新的using类型

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

then you can add a second template parameter, a typename with void as default, in specialize_me_2 然后你可以在specialize_me_2添加第二个模板参数,默认情况下为void的typename

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

and using SFINAE over specialOrType 并使用SFINAE而不是specialOrType

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

you get your working specialization. 你得到你的工作专业。

Instead of myVoidT , starting from C++17, you can obviously use std::void_t . 而不是myVoidT ,从C ++ 17开始,显然可以使用std::void_t

Observe that this way you can't deduce the original T type but you can recover it through specialOrType . 请注意,这样您就无法推断出原始T类型,但您可以通过specialOrType恢复它。

Observe also that this require (as pointed by aschepler) that Or<void> is a valid specialization. 另请注意,这需要(如aschepler所指出的) Or<void>是一个有效的特化。 If this isn't the case, you should choose another type X so that Or<X> is a valid specialization for all Either<T> . 如果不是这种情况,则应选择另一种类型X以便Or<X>是所有Either<T> Suppose that, by example, Or<int> is a valid specialization for every Either<T> , the specialization become 假设,通过示例, 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;
 };

The following is a full working example 以下是一个完整的工作示例

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

Looks like T can't be deduced in your specialization from Either<T>::Or , passing T in as another template parameter appears to make it work, if that is any use too you.. 看起来T不能在您的专业化中推断出来自Either<T>::Or ,传递T in作为另一个模板参数似乎使其工作,如果这是任何使用你...

#include <iostream>

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


template<typename U,template<class> class T>
struct specialize_me_2 {};

template<class T>
struct specialize_me_2<T,Either<T>::template Or> {
    static const int foo = 3;
};


int main() {
    std::cout << specialize_me_2<int,Either<int>::Or >::foo; // Does compile
}

Demo 演示

Which could be made a bit cleaner with a nested type member in Either so you use like, Either使用嵌套类型成员可以使其更清洁,所以你使用like,

using someEitherType = Either<int>;
...
specialize_me_2<someEitherType::type, someEitherType::Or>::foo

Or just specialize on Either directly for the first template parameter, 或者只是直接专注于第一个模板参数,

template<class T>
struct specialize_me_2<Either<T>,Either<T>::template Or> {
    static const int foo = 3;
};

and just pass in 然后传入

specialize_me_2<someEitherType, someEitherType::Or>::foo

Demo2 DEMO2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM