函数模板与重载混合

Function Templating mixed with Overloading

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

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

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

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

对 nested-vector 情况使用部分特化*,对各种 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)
}

(* 是的,我知道学究们会指出,从技术上讲,这不是 "partial specialization" 而是 "partially ordered function overloading"。)

如果您可以接受 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) 的模板 class(请参阅以下示例中的 baz),您可以优先考虑一个或另一个版本(通过示例)传递 int 值并在首选版本中接收 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 
 }