模板部分特化

发布于 2024-10-20 16:32:32 字数 288 浏览 2 评论 0原文

有人知道根据什么规则下面的代码不能编译吗?

template <class T>
struct B
{
    typedef T type;
};

template<class T>
struct X
{
};
template<class T>
struct X<B<T>::type*>//HERE I'M PARTIALLY SPECIALIZING (WELL, TRYING TO...)
{
};

请参阅代码内的注释。

Would any one knows according to what rules code below doesn't compile?

template <class T>
struct B
{
    typedef T type;
};

template<class T>
struct X
{
};
template<class T>
struct X<B<T>::type*>//HERE I'M PARTIALLY SPECIALIZING (WELL, TRYING TO...)
{
};

Please see comment inside the code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蘸点软妹酱 2024-10-27 16:32:32

你认为这会如何运作?编译器将查看某个地方是否有一个类 T 具有您的类的 typedef“类型”?

它只是不会。尽管它是一个指针。

请记住,您的 B 模板可能在某些地方是专门化的,因此该类型并不总是 T*,但它无法通过逆向工程推断出它。

对于那些不完全理解我的答案的人,您要求编译器做的是找到一个类 U,使得 B::type 是您作为参数传入的类。

class Foo;
class Bar;

template<> struct B<Foo>
{
  typedef int type;
};

template<> struct B<Bar>
{
  typedef int type;
};

X<int*> // ambiguous, T is Foo or Bar?

很难确切地知道你为什么要尝试做你现在要做的事情。您可以对所有指针进行部分特化,然后对特定指针进行完全特化,这可以根据另一个模板来实现。

How do you think that will work? The compiler will look to see if there is a class T somewhere that has a typedef "type" to your class?

It just won't. Even though it's a pointer.

Remember that presumably your B template is presumably specialised in places so that type is not always T*, but it can't deduce it with reverse engineering.

For those who did not understand my answer fully, what you are asking the compiler to do is find a class U such that B::type is the class you pass in as a parameter.

class Foo;
class Bar;

template<> struct B<Foo>
{
  typedef int type;
};

template<> struct B<Bar>
{
  typedef int type;
};

X<int*> // ambiguous, T is Foo or Bar?

It is difficult to know exactly why you are trying to do what you are. You can do a partial specialization on all pointers and then a total specialization on specific pointers, which could be implement in terms of another template.

烟燃烟灭 2024-10-27 16:32:32

您需要使用 typename 关键字,

template<class T>
struct X<typename B<T>::type*>
{
};

因为 B::type 是一个从属名称。所以 typename 是必需的!

--

编辑:

即使输入 typename 后,它也不会编译。我认为这是因为对于编译器来说,从 X 中推导 B 中的 T 类型是很困难的,或者可能是不可能的。所以我相信它的非演绎上下文。

请参阅此处的类似示例和讨论:

非推导中的模板参数部分特化中的上下文


但是,如果将特化更改为:

template<class T>
struct X<B<T> >
{
};

那么它就成为可推导的上下文,因此可以编译。

You need to use typename keyword as,

template<class T>
struct X<typename B<T>::type*>
{
};

It's because B<T>::type is a dependent name. So typename is required!

--

EDIT:

Even after putting typename, it isn't compiling. I think it's because deduction of type T in B<T> from X<U> is difficult, or possibly impossible, for the compiler. So I believe its non-deduced context.

See a similar example here and the discussion:

Template parameters in non-deduced contexts in partial specializations


However, if you change the specialization to this:

template<class T>
struct X<B<T> >
{
};

Then it becomes the deducible context, and so would compile.

甜味拾荒者 2024-10-27 16:32:32

假设您已经按照 Nawaz 的建议添加了 typename

您遇到的错误消息中准确地解释了该问题:“模板参数在部分特化 B::type* 中不可推导。问题在于 B:: typeT 对于所有类型 T 都完全相同:考虑以下示例:

class MyClass1 {};
typedef typename B<MyClass>::type MyClass2; //(*)

X<MyClass*> obj1;
X<MyClass2*> obj2;

(*) 的结果是类型 MyClass2 本质上是 MyClass1 因此,obj1obj2 应该是同一类的对象 现在,模板 的版本。 >X 他们应该使用吗?

如果您期望使用 X 的专用版本,请告诉我如果删除 (*) 行,答案是否应该相同(显然 obj2 也是如此)。仍然 obj1 应该是 X 的专门版本,如行 (*) 。 。

但现在我们希望编译器能够检测到某些类型可能被声明为 B::type,尽管我们从未这样做过 我们希望编译器验证所有可能的模板实例化,以检查其中之一是否没有奇怪的 typedef。

我希望这能澄清为什么编译器无法处理这种专业化。


可能有帮助的替代方案

我相信您的问题可以通过创建一个特征类来显式标记应该以特殊方式处理的类型来解决。像这样的事情:

template <bool v>
struct boolean_value {
  static const bool value=v;
};

template <typename T>
struct is_my_interesting_type : public boolean_value<false> {};

class MyClass {
  ...
};

template <>
struct is_my_interesting_type<MyClass> : public boolean_value<true> {};

template <typename T, bool special>
class  InternalX {
  ... //generic version of your template X
};

template <typename T>
class InternalX<T,true> {
  ... //special version of your template X
};

template <typename T>
class X : public InternalX<T,is_my_interesting_type<T>::value> {};

另外,您可能会对 boost 库中的操作方式感兴趣,特别是 Boost.Type_Traits

Assuming you already added typename as suggested by Nawaz.

The problem is exactly explained in the error message you encounter: "template parameter is not deducible in partial specialization B<T>::type*. The problem is that B<T>::type and T is exactly the same for all types T. Consider the following example:

class MyClass1 {};
typedef typename B<MyClass>::type MyClass2; //(*)

X<MyClass*> obj1;
X<MyClass2*> obj2;

The result of line (*) is a type MyClass2 which is essentially MyClass1. So, obj1 and obj2 should be objects of the same class. Now, which version of template X should they use?

If you would expect the specialised version of X, tell me if the answer should be the same if line (*) is removed (and obviously obj2 as well). Still obj1 should be the specialised version of X as line (*) has nothing to do with it.

But now we expect the compiler to detect that some type can be potentially declared as B<T>::type although we never do this. We expect the compiler to verify all possible template instantiations to check if there is no strange typedef in one of them.

I hope this clarifies why such specialisation cannot be handled by the compiler.


An alternative that might help

I believe your problem could be attacked by creating a trait class for explicitly marking types that should be handled in a special way. Something like this:

template <bool v>
struct boolean_value {
  static const bool value=v;
};

template <typename T>
struct is_my_interesting_type : public boolean_value<false> {};

class MyClass {
  ...
};

template <>
struct is_my_interesting_type<MyClass> : public boolean_value<true> {};

template <typename T, bool special>
class  InternalX {
  ... //generic version of your template X
};

template <typename T>
class InternalX<T,true> {
  ... //special version of your template X
};

template <typename T>
class X : public InternalX<T,is_my_interesting_type<T>::value> {};

Also, you might be interesting how it is done in boost library, in particular Boost.Type_Traits

温柔嚣张 2024-10-27 16:32:32

“参数列表不能与非专用参数列表相同(它必须专门化某些东西)”
请参阅en.cppreference.com 上的partial_specialization

"The argument list cannot be identical to the non-specialized argument list (it must specialize something)"
see partial_specialization at en.cppreference.com

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文