通常,您可以针对实例化的模板类部分地专门化模板类。例如
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
实例化T
时,专业化是 not 。我的猜测是,这是因为编译器必须确认或拒绝,&#34;存在T
,Either<T>::template Or
与specialize_me_2
实例化的类型相同&#34;为了选择我的专业化,它没有编程也没有指定这样做。
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
实例化,就会选择专精化?
此Either<T>
结构最终将表示携带错误的类型,因此T
表示Either<T>::Or<U>
是错误类型,U
表示#define
是成功计算所携带的类型。
如果这是不可能的,我可能仍然可以使用Either<T>
来为每个T
定义#define
,因为specialize_me_2
也是Either<T>::Or
包括该特定Either
的{{1}}专精。实际上,我打算在程序中使用template<class T> using FooError = Either<Foo>::Or<T>
结构,然后写FooError<Bar>
,然后写FooError<Quux>
, const mergeStrings = (...strings) => strings.join(" ");
等等,所以使用它不会与预期用途的巨大突破。
答案 0 :(得分:1)
有趣的问题。
要解决它而不会太痛苦...如果您可以在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; };
并使用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;
};
你获得了工作专业。
而不是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;
}
答案 1 :(得分:0)
在Either<T>::Or
的专业化中无法推断T,传递T
,因为另一个模板参数似乎可以使其正常工作,如果你有任何用处的话......
#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
}
使用Either
中的嵌套类型成员可以使其更清晰,所以你使用like,
using someEitherType = Either<int>;
...
specialize_me_2<someEitherType::type, someEitherType::Or>::foo
或者只是直接专注于第一个模板参数,
template<class T>
struct specialize_me_2<Either<T>,Either<T>::template Or> {
static const int foo = 3;
};
然后传入
specialize_me_2<someEitherType, someEitherType::Or>::foo