函数模板与重载混合

时间:2017-02-12 20:09:08

标签: c++ templates overloading

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

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

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

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

2 个答案:

答案 0 :(得分:2)

对嵌套向量的情况使用部分特化*,对各种特征类使用一般情况,如下所示:

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

(*是的,我知道学生们会指出,从技术上讲,这不是&#34;部分专业化&#34;但是&#34;部分有序的功能重载&#34;。)

答案 1 :(得分:1)

如果您可以接受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),您可以优先考虑一个版本或另一个版本(例如)一个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 
 }