Partial Specialization of Operator()

落花浮王杯 提交于 2019-12-05 01:44:07

问题


One of my classes declares a templated function:

template<class A, class B>
A do_something(const std::vector<B> &data)

which I'd like to partially specialize on typename A. B is a family of types that implement a pretty minimal interface, and we use a lot of them, so I'd like my specialization to be generic on B. I suspect this is doubly vexing as typename A is used only as the return type.

From the internet, I've gleaned that I can't partially specialize a function, so I've created a class as follows:

template<class A, class B> 
class do_something_implementation {
  public:
    do_something_implementation(const std::vector<B> &data_) {
      data = data_;
    }

  int do_something_implementation<int, B>::operator()() {
    /* Complicated algorithm goes here... */
  }

  double do_something_implementation<double, B>::operator()() {
    /* Different complicated algorithm goes here... */
  }

  private:
      std::vector<B> data;
}

When I try to compile that (using Visual Studio 2008), the compiler crashes (!) and I get the following error:

fatal error C1001: An internal error has occurred in the compiler.

I assume this is my problem and not the compiler's. Is there a better way to express the partial specialization I'm aiming for?


回答1:


Usually, it goes like this:

template <typename A, typename B>
struct DoSomethingHelper
{
    static A doIt(const std::vector<B> &data);
};

template <typename B>
struct DoSomethingHelper<double, B>
{
    static double doIt(const std::vector<B> &data) { ... }
};

template <typename B>
struct DoSomethingHelper<int, B>
{
    static int doIt(const std::vector<B> &data) { ... }
};

template<class A, class B>
A do_something(const std::vector<B> &data)
{ return DoSomethingHelper<A, B>::doIt(data); }



回答2:


Now that you've seen the classic forward to static method, there is actually another way when the type for which to specialize is "complete".

You may not be able to partially specialize a function, but you can perfectly overload it.

template <typename A, typename B>
A do(std::vector<B> const& data) { return this->doImpl(data, (A*)0); }

template <typename A, typename B>
A doImpl(std::vector<B> const& B, A*) { // generic implementation }

template <typename B>
int doImpl(std::vector<B> const& B, int*) { // int implementation }

template <typename B>
double doImpl(std::vector<B> const& B, double*) { // double implementation }

The trick is to pass an "unused" argument to doImpl for the sole purpose of actually selecting the right implementation (thanks to overload resolution).

Here I simply chose to pass (A*)0, because this does not involve A's constructor (in case it's non trivial).

This dispatch idiom is what is used in the STL to implement some algorithm with better efficiency for some iterator categories (for example, std::distance is O(1) for random iterators).

I find it much more lightweight that using a helper class with static methods and partial specializations... but maybe that's just me :)




回答3:


People typically just forward to a static implementation.

template<class A, class B> class X;
template<class A, class B> friend class X;
template<class A, class B> class X {
public:
    static A do_something(class_type* not_this, const std::vector<B>& data) {
        //...
    }
};
// partially specialize
template<class A, class B>
A do_something(const std::vector<B> &data) {
    return X<A, B>::do_something(this, data);
};



回答4:


Not a solution to your problem (there are a couple already there), but some of the things that are wrong in your code:

You are missing a struct or class keyword in the template class declaration:

template <typename A, typename B> struct do_something_implementation {
//                                ^^^^^^

Inside the class definition, member functions must not use a qualified name, regardless of whether the class is a template or not:

class A {
   void A::foo() {} // Error, should be: void foo() {}
};

Member template specializations cannot appear inside the class definition, but at the namespace level:

class B {
   template <typename T> void foo( T );
};
template <> void B::foo<int>( int ) {}
template <> void B::foo<double>( double ) {}

Plus on your case, the member function is not a template, but rather a non-templated member function (the template is the containing class, not the function itself). What your code is effectively trying to do is defining other class' member functions inside the general template, kind of trying to do.

Overall there was enough errors to make parsing the code almost impossible for the compiler to identify what you were trying to do and provide a good error message, but still, it should have provided any error message pointing to the first line that you copied instead of chocking to death.



来源:https://stackoverflow.com/questions/4440165/partial-specialization-of-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!