运算符()的部分特化

发布于 2024-10-07 05:54:02 字数 1048 浏览 8 评论 0原文

我的一个类声明了一个模板化函数:

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

我想部分专门研究typename AB 是一个实现非常简单的接口的类型系列,我们使用了很多这样的接口,所以我希望我的专业化在 B 上是通用的。我怀疑这更加令人烦恼,因为 typename A 仅用作返回类型。

从互联网上,我了解到我无法部分专门化一个函数,因此我创建了一个类,如下所示:

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

当我尝试编译该类(使用 Visual Studio 2008)时,编译器崩溃(!)并且我得到以下错误:

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

我认为这是我的问题而不是编译器的问题。有没有更好的方法来表达我所追求的部分专业化?

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?

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

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

发布评论

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

评论(4

怀里藏娇 2024-10-14 05:54:02

通常,它是这样的:

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

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); }
鸠书 2024-10-14 05:54:02

现在您已经了解了经典的转发到静态方法,当要专门化的类型是“完整”时,实际上还有另一种方法。

您可能无法部分特化某个函数,但您可以完美地重载它。

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 }

诀窍是将“未使用”的参数传递给 doImpl,其唯一目的是实际选择正确的实现(感谢重载解析)。

这里我只是选择传递 (A*)0,因为这不涉及 A 的构造函数(以防它不重要)。

STL 中使用此调度惯用法来实现某些对某些迭代器类别具有更高效率的算法(例如,对于随机迭代器,std::distance 为 O(1))。

我发现它比使用具有静态方法和部分专业化的辅助类要轻量得多...但也许这只是我的问题:)

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

复古式 2024-10-14 05:54:02

人们通常只是转向静态实现。

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

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);
};
染墨丶若流云 2024-10-14 05:54:02

不是您问题的解决方案(已经有几个),而是您的代码中存在一些错误:

您缺少 structclass 关键字模板类声明:

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

在类定义内部,成员函数不得使用限定名称,无论该类是否是模板:

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

成员模板专业化不能出现在类定义内部,但出现在命名空间级别:

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

根据您的情况加上,成员函数不是模板,而是非模板化成员函数(模板是包含类,而不是函数本身)。您的代码实际上试图做的是在通用模板中定义其他类的成员函数,有点试图做。

总体而言,存在足够多的错误,使得编译器几乎不可能解析代码来识别您想要执行的操作并提供良好的错误消息,但它仍然应该提供指向该代码的任何错误消息你复制的第一行而不是被噎死。

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.

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