了解(简单?)C ++部分模板专业化 [英] Understanding (simple?) C++ Partial Template Specialization

查看:50
本文介绍了了解(简单?)C ++部分模板专业化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:这似乎是一个问题的转贴: C ++-重载了模板化的类方法,并对该方法进行了部分说明

Note: this seems to be a repost of a problem: C++ - Overload templated class method with a partial specilization of that method

我将C ++模板专业化的问题归结为一个简单的案例。

I have boiled down a problem I am having with C++ template specialization down to a simple case.

它包含一个简单的2参数模板类事物,我想专门研究 Thing< A,B> :: doSomething() for B = int

It consists of a simple 2-parameter template class Thing, where I would like to specialize Thing<A,B>::doSomething() for B=int.

#include <cstdio>

// A 3-parameter template class.
template <class A, class B>
class Thing
{
public:
    Thing(A a, B b) : a_(a), b_(b) {}
    B doSomething();
private:
    A a_;
    B b_;
};

// The generic case works as expected.
template <class A, class B>
B Thing<A,B>::doSomething()
{
    return b_;
}

// This specialization does not work!
template <class A>
int Thing<A,int>::doSomething()
{
    return b_+1;
}

int main() {
    // Setup our thing.
    Thing<double,int> thing(1.0,2);
    // This doesn't compile - but works with the generic case.
    printf("Expecting 3, and getting %i\n", thing.doSomething());
    // Clean up.
    return 0;
}

不幸的是, g ++ 退出并出现错误:

Unfortunately, g++ exits with the error:

partial_specialization.cpp:30: error: invalid use of incomplete type ‘class Thing<A, int>’
partial_specialization.cpp:8: error: declaration of ‘class Thing<A, int>’

clang ++ 编译器较为冗长,但存在相同的问题:

The clang++ compiler is a bit more verbose, but has the same problem:

partial_specialization.cpp:30:19: error: nested name specifier 'Thing<A, int>::' for declaration does not
      refer into a class, class template or class template partial specialization
int Thing<A,int>::doSomething()
    ~~~~~~~~~~~~~~^
partial_specialization.cpp:32:12: error: use of undeclared identifier 'b_'
    return b_+1;
           ^
2 errors generated.

我已阅读并了解,不允许对函数进行部分模板专门化-但我认为在这种情况下,部分专注于事物的类。

I have read and understood that partial template specializations on functions aren't allowed - but I thought I was partially specializing over classes of Thing in this case.

有任何想法吗?

我做了什么:一种解决方法,根据接受的答案提供的链接确定:

What I did: A workaround, as determined from the link provided by the accepted answer:

template< class T >
inline T foo( T const & v ) { return v; }

template<>
inline int foo( int const & v ) { return v+1; }

// The generic case works as expected.
template <class A, class B>
B Thing<A,B>::doSomething()
{
    return foo(b_);
}


推荐答案

函数模板的部分专业化标准不允许使用成员函数模板或独立函数模板,

Partial specialization of a function template, whether it is member function template or stand-alone function template, is not allowed by the Standard:

template<typename T, typename U> void f() {} //okay  - primary template
template<typename T> void f<T,int>() {}      //error - partial specialization
template<> void f<unsigned char,int>() {}    //okay  - full specialization

但是您可以部分专门化类模板本身。您可以执行以下操作:

But you can partially specialize the class template itself. You can do something like this:

template <class A>
class Thing<A,int>  //partial specialization of the class template
{
    //..
    int doSomething();
};

template <class A>
int Thing<A,int>::doSomething()  { /* do whatever you want to do here */ }

请注意,当您部分专业化类模板时,成员函数的模板参数列表(在类之外的定义中)必须必须匹配类模板的部分专业化。这就是说,对于类模板的上述部分专业化,您不能定义以下内容:

Note that when you partially specialize a class template, then the template parameter-list of member function (in its definition outside the class), must match the template parameter list of the class template partial specialization. That means, for the above partial specialization of the class template, you cannot define this:

template <class A>
int Thing<A,double>::doSomething(); //error

这是不允许的,因为函数定义中的模板参数列表与类模板部分专业化的模板参数列表。 Standard(2003)的第14.4.5.3/1条说,

Its not allowed, because the template parameter-list in function definition didn't match the template parameter-list of the class template partial specialization. §14.5.4.3/1 from the Standard (2003) says,


类模板部分专业化成员的模板参数列表应匹配类模板部分特化的模板参数列表。[...]

The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.[...]

有关更多信息这,在这里阅读我的答案:

For more on this, read my answer here:

C ++-重载了模板化的类方法,并对该方法进行了部分说明

那么解决方案是什么?您是否会对所有重复工作进行部分专业化处理?

So what is the solution? Would you partially specialize your class along with all the repetitive work?

一个简单的解决方案是工作委托,而不是部分地进行类化模板化。编写一个独立函数模板并将其专门化为:

A simple solution would be work delegation, instead of partially specializing the class template. Write a stand-alone function template and specialize this as:

template <class B>
B doTheActualSomething(B & b) { return b;  }

template <>
int doTheActualSomething<int>(int & b) { return b + 1; }

然后从 doSomething()成员函数为:

template <class A, class B>
B Thing<A,B>::doSomething() { return doTheActualSomething<B>(b_); }






由于您的特殊情况, doTheActualSomething 只需要知道一个成员的值,即 b _ ,上述解决方案就可以了,因为您可以将值作为参数传递给函数,其类型为模板 type 参数 B ,而专门化为 int 可能是完全专业化的。


Since in your particular case, doTheActualSomething needs to know the value of only one member, namely b_, the above solution is fine, as you can pass the value to the function as argument whose type is the template type argument B, and specialization for int is possible being it full-specialization.

但是想象一下,如果它需要访问多个成员,每个成员的 type 取决于模板的 type 参数列表,然后定义一个独立的函数模板并不能解决问题,因为现在将有多个 type 参数函数模板,并且您不能部分仅将函数专门化为一种类型(因为不允许这样做)。

But imagine if it needs to access multiple members, type of each depends on the template type argument-list, then defining a stand-alone function template wouldn't solve the problem, because now there will be more than one type argument to the function template, and you cannot partially specialize the function for just, say, one type (as its not allowed).

因此,在这种情况下,您可以定义一个类模板,该类模板定义一个静态的非模板成员函数 doTheActualSomething 。方法如下:

So in this case you can define a class template instead, which defines a static non-template member function doTheActualSomething. Here is how:

template<typename A, typename B>
struct Worker
{
   B doTheActualSomething(Thing<A,B> *thing)
   {
      return thing->b_;
   }
};

//partial specialization of the class template itself, for B = int
template<typename A>
struct Worker<A,int>
{
   int doTheActualSomething(Thing<A,int> *thing)
   {
      return thing->b_ + 1;
   }
};

请注意,您可以使用东西指向访问该课程的任何成员。当然,如果需要访问私有成员,则必须将 struct Worker 设为 Thing 类的朋友模板,例如:

Notice that you can use thing pointer to access any member of the class. Of course, if it needs to access private members, then you've to make struct Worker a friend of Thing class template, as:

//forward class template declaration
template<typename T, typename U> struct Worker

template <class A, class B>
class Thing
{
    template<typename T, typename U>  friend struct Worker; //make it friend
   //...
};

现在将作品委托给朋友为:

Now delegate the work to the friend as:

template <class A, class B>
B Thing<A,B>::doSomething()
{
    return Worker<A,B>::doTheActualSomething(this); //delegate work
}

此处需要注意两点:


  • 在此解决方案中, doTheActualSomething 不是成员函数 template 。它不是封闭的类,它是模板。因此,我们可以随时 partially 专业化类模板,以获得 partial 成员函数模板专业化的理想效果。

  • this 指针作为函数的参数传递,我们可以访问类 Thing< A,B> 的任何成员,甚至是私人成员,因为 Worker< T,U> 也是朋友。

  • In this solution, doTheActualSomething is not a member function template. Its not enclosing class which is template. Hence we can partially specialize the class template anytime, to get the desired effect of the partial member function template specialization.
  • Since we pass this pointer as argument to the function, we can access any member of the class Thing<A,B>, even private members, as Worker<T,U> is also a friend.

完整的在线演示: http://www.ideone.com/uEQ4S

现在仍有改善的机会。现在, Worker 类模板的所有实例都是 Thing 类模板的所有实例的朋友。因此,我们可以将这种多对多友谊限制为:

Now there is still a chance of improvement. Now all instantiations of Worker class template are friends of all instantiation of Thing class template. So we can restrict this many-to-many friendship as:

template <class A, class B>
class Thing
{
    friend struct Worker<A,B>; //make it friend
   //...
};

现在仅 Worker 类模板的一个实例是 Thing 类模板的一个实例的朋友。那是一对一的友谊。即, Worker< A,B> Things< A,B> 的朋友。 Worker< A,B> 不是 Thing< A,C> 的朋友。

Now only one instantiation of Worker class template is a friend of one instantiation of Thing class template. That is one-to-one friendship. That is, Worker<A,B> is a friend of Thing<A,B>. Worker<A,B> is NOT a friend of Thing<A,C>.

此更改要求我们以略有不同的顺序编写代码。请参见完整的演示,其中包括类和函数定义的所有排序以及所有内容:

This change requires us to write the code in somewhat different order. See the complete demo, with all the ordering of class and function definitions and all:

http://www.ideone.com/6a1Ih

这篇关于了解(简单?)C ++部分模板专业化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆