【问题标题】:Function Templating mixed with Overloading函数模板与重载混合
【发布时间】:2017-02-12 20:09:07
【问题描述】:

所以我想创建一个函数,将文本文件中的数据读取到各种矩阵中。
第一个是Eigen 矩阵,您可以在其中访问带括号的元素。
例如。 mat(1,2)。第二种是vector<vector<T>之类的类型,其中T可以是intdouble等。显然它们是用方括号访问的。

现在我需要为这两种情况创建一个模板。 Eigen 有很多矩阵类型(MatrixXdSparseMatrix 等),vector<vector<T>> 可以有很多类型 T

但是,当我真正想要的是vector<vector<T>> 的模板函数时,如何确保不会调用Eigen 的模板函数?

我知道重载优先于模板化,但它们都是模板化的!
我该怎么办?

【问题讨论】:

    标签: c++ templates overloading


    【解决方案1】:

    对嵌套向量情况使用偏特化*,对各种 Eigen 类使用一般情况,如下所示:

    template <typename T>
    void foo(vector<vector<T>>& mat) {
        // code that uses mat[x][y]
    }
    
    template <typename T>
    void foo(T& mat) {
        // code that uses mat(x,y)
    }
    

    (* 是的,我知道学究会指出,从技术上讲,这不是“部分特化”而是“部分有序函数重载”。)

    【讨论】:

    • 所以我不明白为什么当我们申请vector&lt;vector&lt;T&gt;&gt; 对象时会调用第一个模板函数。是因为它是先定义的吗?似乎第一个功能“更专业”或vector&lt;vector&lt;T&gt;&gt;:这是为什么?什么规则可以解决歧义?
    • 您所写的内容似乎确实有效。我为vector&lt;T&gt; 编写了第三个模板函数,它似乎在这三个选项之间做出了正确的决定。我只是不想在不知道它是如何工作的情况下使用它并且有一天会出错。
    • 是的,更专业的重载获胜。详细规则可以在 C++ 标准中标记为 [temp.deduct.partial] 的部分中找到(当前草案中的第 14.8.2.4 节;在早期版本中可能有不同的编号)。在模棱两可的情况下(例如,如果有两个参数,在不同的重载中以不同的方式专门化),有时会出现编译错误,因为编译器无法明确选择一个“最专门化”的版本,但在这种情况下,总是很清楚哪个一个被选中。
    【解决方案2】:

    如果您可以接受 C++11 解决方案,那么使用 SFINAE 检查 T 类型是否支持 T()(0U, 0U)T()[0U][0U] 怎么样?

    如果T 不支持这两种操作,这应该可以工作。

    以下是一个工作示例(bar 替代 Eigen

    #include <vector>
    #include <iostream>
    
    template <typename T>
    auto foo (T & mat) -> decltype( mat[0U][0U], int() ) 
     { return 1; }
    
    template <typename T>
    auto foo (T & mat) -> decltype( mat(0U, 0U), int() ) 
     { return 2; }
    
    struct bar
     {
       void operator() (std::size_t x, std::size_t y)
        { }
     };
    
    int main ()
     {
       std::vector<std::vector<int>>  m1;
       bar                            m2;
    
       std::cout << foo(m1) << std::endl; // print 1
       std::cout << foo(m2) << std::endl; // print 2
     }
    

    如果您必须使用同时支持[0U][0U](0U, 0U) 的模板类(请参阅以下示例中的baz),您可以优先考虑一个版本或另一个通过(通过示例)@987654331 @值并在首选版本中接收int,在其他版本中接收long

    示例见以下代码

    #include <vector>
    #include <iostream>
    
    template <typename T>
    auto foo (T & mat, long) -> decltype( mat[0U][0U], int() ) 
     { return 1; }
    
    template <typename T>
    auto foo (T & mat, int) -> decltype( mat(0U, 0U), int() ) 
     { return 2; }
    
    template <typename T>
    int foo (T & mat)
     { return foo(mat, 0); }
    
    
    struct bar
     {
       void operator() (std::size_t x, std::size_t y)
        { }
     };
    
    struct baz
     {
       std::vector<std::vector<int>> m;
    
       std::vector<int> & operator[] (std::size_t x)
        { return m[x]; }
    
       int & operator() (std::size_t x, std::size_t y)
        { return m[x][y]; }
     };
    
    int main ()
     {
       std::vector<std::vector<int>>  m1;
       bar                            m2;
       baz                            m3;
    
       std::cout << foo(m1) << std::endl; // print 1
       std::cout << foo(m2) << std::endl; // print 2
       std::cout << foo(m3) << std::endl; // print 2 
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-02
      • 1970-01-01
      • 2019-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多