IMO,C++ 模板规则似乎过于严格,并且定义了编译器实现。但在这里我有一个特定的行为,我很难理解。
在下面的问题中,我有意识地尽量避免显式特化父类。
问题是,我可以部分特化一个成员,但不能完全特化它。这确实违反直觉,因为您可以轻松地将虚拟模板添加到完全专用的模板并使其部分专用。这是怎么回事?
这很重要,因为,正如我们所知,如果不对类也进行特化,就不能对成员函数进行特化(这可以看作是这个问题的组合,需要部分特化,而 c++ 不需要允许部分专门化的功能。我不知道这些是否相关但至少它们是一致的),因此如果你想在你的类中有一个你可以专门化的函数体,你就只能使用仿函数。最重要的是,您需要添加一个虚拟模板参数才能使其正常工作!
这个有效:
template <class T>
class A
{
template<typename Y, typename Z>
struct C{
void operator()(int x);
};
template<typename Z>
struct C<int, Z>{
void operator()(int x);
};
};
template <class T>
template <typename Z>
void A<T>::C<int, Z>::operator()(int x){
}
但这不是:
template <class T>
class A
{
template<typename Y>
struct C{
void operator()(int x);
};
template<>
struct C<int>{
void operator()(int x);
};
};
template <class T>
template <>
void A<T>::C<int>::operator()(int x){
}
Sean F. 在评论中指出编译器很难选择特化。但这里的问题是部分特化并不能解决这个问题。所以这不是答案。
最佳答案
一般来说,模板函数特化不是一个好主意。使用重载或标签调度。例如:
template<class T>struct tag_t{};
template<class T>
auto foo(T& t){ return foo( tag_t<T>{}, t ); }
现在我们可以使用重载来调度:
void foo( tag_t<int>, int& i ){ i+=3; }
template<class T>
void foo( tag_t<T>, T& t ){ t*=2; }
这里没有特化。我们使用重载决议规则来选择实现。这对成员来说效果很好。
我们只对顶级类使用特化。即使在那里,我也经常想通过标签分派(dispatch)和使用 decltype 来选择实现,因为重载解析通常会提供更好的模式匹配。
如果您确实需要一个成员类,请将您的成员类替换为一个顶级类和一些友元声明。
template<class T, class Y>
struct A_C;
template <class T>
class A
{
template<class T0, class Y0>
friend class A_C<T0, Y0>;
template<class Y>
using C=A_C<T,Y>;
};
template<class T, class Y>
struct A_C {
// implementation of A::C
};
现在你在这里对 A_C
进行了非常无限制的特化。没有你的问题。
关于c++ - 为什么我可以部分特化但不能完全特化 C++ 中的成员模板?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50731409/