【问题标题】:Call the unspecialized version of a function when specializing it in C++?在 C++ 中专门化时调用函数的非专门化版本?
【发布时间】:2010-11-04 17:04:28
【问题描述】:

假设我有一个模板类:

template <typename T>
class foo {
  void do_someting(T obj) {
    // do something generic...
  }
};

我想专门化 do_something,但在其中我想调用“正常”的 do_something 函数:

template<>
void foo<MyObj>::do_something(MyObj obj) {
  // do something specific...
  // and ALSO do something generic!
}

有没有办法在我的专用函数中引用 do_something 的正常版本?还是我只需要复制代码?

(我知道我可以重构 foo,这样我就不会遇到这个确切的问题,但碰巧我不能真正修改“真正的”foo,因为它是高度共享的代码。)

【问题讨论】:

  • 对于MyObj 类型没有“正常”版本的do_something - 模板特化的全部效果是替换您将获得的实例化基本模板,带有您在专业化中定义的类/函数。
  • 对,但是编译器知道 foo::do_something 中的代码,它没有理由不让我以某种方式引用它。不过,我完全愿意相信这种语言功能根本不存在——这就是我想要找出的。
  • @Steve Townsend——这是一个不同的问题。那就是问你如何才能拥有一个具有一些专门功能和一些非专门功能的类。
  • “它没有理由不让我以某种方式引用它” - 如果模板以完全不同的方式定义,那就没有理由了。事实上,foo&lt;MyObj&gt; 是一个类,它有一个 do_something 函数,并且该函数由特化定义。如果使用参数MyObj 实例化基本模板foo,则结果将是另一个 类,也是foo&lt;MyObj&gt;,这是不允许的,这就是障碍。我想如果该语言以某种方式让您将基本模板实例化为不同的名称,您可能会没事,但没有这样的运气。

标签: c++ templates template-specialization


【解决方案1】:

没有。您的专业化是 MyObj 类型参数存在的唯一定义。但是,考虑以这种方式修改 foo 模板,这将对模板的当前用户透明:

template<typename T>
class foo {
  void prelude(T &obj){ // choose a better name
    /* do nothing */
  }
  void do_something(T obj){
    prelude(obj);
    // do something generic...
  }
};

然后为前奏定义一个特化:

template<>
void foo<MyObj>::prelude(MyObj &obj){
  // do something specific
}

这在结构上与main use case for private virtual members 有点相似。 (有点。不是真的。但这就是我在这个答案中的灵感。)

【讨论】:

  • 这看起来确实像 Sutter 的 NVI 的模板世界类比!
【解决方案2】:

您也可以考虑一种不是 MyObj 的类型,但隐式转换为它,但最好的方法是重构并可能提取通用泛型的东西。

#include <iostream>
#include <boost/ref.hpp>
typedef int MyObj;


template <typename T>
struct foo {
  void do_something(T obj) {
    // do something generic...
    std::cout << "generic " << obj << '\n';
  }
};

template<>
void foo<MyObj>::do_something(MyObj obj) {
  // do something specific...
  std::cout << "special " << obj << '\n';
  // and ALSO do something generic!
  foo<boost::reference_wrapper<MyObj> >().do_something(boost::ref(obj));
}

int main()
{
    foo<int> f;
    f.do_something(10);
}

【讨论】:

    【解决方案3】:

    是的,这实际上非常简单。您只需让函数的主要通用版本作为“实现”通用函数的传递,不会部分专门化,然后您可以从根据需要初始化函数。

    template <typename T>
    class foo 
    {
      void do_something(T obj) 
      {
         do_something_impl(obj);
      }
    
      void do_something_impl(T obj)
      {
        // do something generic...
      }
    };
    

    现在专业化可以毫无问题地调用通用版本:

    template<>
    void foo<MyObj>::do_something(MyObj obj) 
    {
      // do something specific...
      do_something_impl(obj); //The generic part
    }
    

    我认为这比 Steve M. 的回答更接近你的初衷,这也是我在遇到这个问题时所做的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-05
      • 2020-11-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多