【问题标题】:Member function overloading/template specialization issue成员函数重载/模板特化问题
【发布时间】:2011-01-05 18:48:10
【问题描述】:

我一直在尝试调用重载的table::scan_index(std::string, ...) 成员函数,但没有成功。为了清楚起见,我已经删除了所有不相关的代码。

我有一个名为 table 的类,它有一个名为 scan_index() 的重载/模板化成员函数,以便将字符串作为特殊情况处理。

class table : boost::noncopyable
{
public:
    template <typename T>
    void scan_index(T val, std::function<bool (uint recno, T val)> callback) {
        // code
    }

    void scan_index(std::string val, std::function<bool (uint recno, std::string val)> callback) {
        // code
    }
};

然后有一个hitlist 类,它有许多调用table::scan_index(T, ...) 的模板化成员函数

class hitlist {
public:
    template <typename T>
    void eq(uint fieldno, T value) {
        table* index_table = db.get_index_table(fieldno);
        // code
        index_table->scan_index<T>(value, [&](uint recno, T n)->bool {
            // code
        });
    }
};

最后是启动它的代码:

hitlist hl;
// code
hl.eq<std::string>(*fieldno, p1.to_string());

问题是它调用模板化版本而不是调用table::scan_index(std::string, ...)。我尝试过同时使用重载(如上所示)和专用函数模板(如下),但似乎没有任何效果。盯着这段代码几个小时后,我觉得我错过了一些明显的东西。有什么想法吗?

    template <>
    void scan_index<std::string>(std::string val, std::function<bool (uint recno, std::string val)> callback) {
        // code
    }

更新: 我从scan_index() 电话中删除了&lt;T&gt; 装饰。结果是带有字符串参数的调用编译得很好,但是使用其他类型(例如双精度)的调用导致以下错误:

cannot convert parameter 1 from 'double' to 'std::string'

所以我又回到了使用模板专业化。现在我得到这个错误:

error C2784: 'void table::scan_index(T,std::tr1::function<bool(uint,T)>)' :
  could not deduce template argument for 'std::tr1::function<bool(uint,T)>'
  from '`anonymous-namespace'::<lambda5>'

仅供参考:我使用的是 VC++ 10.0

解决方案: 我通过从table 类中删除模板化的scan_index() 函数并简单地编写四个重载函数(其中三个除了签名相同)来解决这个问题。幸运的是,它们都很短(不到十行),所以还不错。

【问题讨论】:

标签: c++ templates overloading specialization


【解决方案1】:

您在此处显式调用模板化成员:

index_table->scan_index<T>(value, [&](uint recno, T n)...

由于value 是模板参数,您应该可以将其替换为:

index_table->scan_index(value, [&](uint recno, T n)...

【讨论】:

    【解决方案2】:

    您不应该明确指定模板参数 - 您应该将其留给模板参数推导和重载决议。这应该允许您在原始代码中发布的重载被拾取和使用。

    【讨论】:

      【解决方案3】:

      准备了这个简化测试(抱歉,我没有 C++0x 编译器 atm):

      class table
      {
      public:
          template <typename T>
          void scan_index(T val) {
              std::cout << "template\n";
          }
      
          template <>
          void scan_index<int>(int val) {
              std::cout << "specialization\n";
          }
      
          void scan_index(int val) {
              std::cout << "overloaded\n";
          }
      };
      
      class hitlist {
      public:
          template <typename T>
          void eq(T value) {
              table tbl;
              tbl.scan_index<T>(value);
          }
      };
      
      int main(int argc, char* argv[])
      {
          int i = 0;
          hitlist hl;
          hl.eq(i);
          return 0;
      }
      

      输出是“专业化”(VC9)。这是因为 hitlist::eq 显式使用模板版本,所以只会考虑模板特化。如果您将tbl.scan_index&lt;T&gt;(value); 更改为tbl.scan_index(value);,则会调用重载版本。

      tbh 我不知道为什么您的模板专业化不起作用,可能是因为 lambda,而不是完整的 C++0x 支持?哪个编译器?

      【讨论】:

      • 这与C++0x无关。问题与选择重载有关,他的 lambda 代码完全有效。
      • “我尝试过同时使用重载(如上所示)和专用函数模板(下)”这就是为什么我认为它与 lambdas 相关
      • 这仅在 Visual C++ 上编译,因为允许类内特化的扩展。对于其他编译器(例如 GCC),特化必须在类之外定义。 (见stackoverflow.com/a/2098016/2319122.
      【解决方案4】:

      模板专业化是不是类似于:

      template <typename T>
      void scan_index(T val, std::function<bool (uint recno, T val)> callback) {
          // code
      }
      template <>
      void scan_index(std::string val, std::function<bool (uint recno, std::string val)> callback) {
          // code
      }
      

      C++ 编译器通过这种方式识别 scan_index 具有专门化而不是寻找重载方法。而且我相信,如果您希望以您可以编码的方式使用它,您可能应该将专门的代码放在模板之前,如下所示:

          void scan_index(std::string val, std::function<bool (uint recno, std::string val)> callback) {
              // code
          }
      template <typename T>
          void scan_index(T val, std::function<bool (uint recno, T val)> callback) {
              // code
          }
      

      【讨论】:

        猜你喜欢
        • 2015-02-27
        • 2012-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多