开发者

Partial Specialization of Operator()

开发者 https://www.devze.com 2023-01-30 06:54 出处:网络
One of my classes declares a templated function: template<class A, class B> A do_something(const std::vector<B> &data)

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?


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); }


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 :)


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);
};


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号