函数模板与重载混合
Function Templating mixed with Overloading
所以我想创建一个函数,将文本文件中的数据读取到各种矩阵中。
这首先是一个 Eigen
矩阵,您可以在其中访问带括号的元素。
例如。 mat(1,2)
。第二种是像 vector<vector<T>
这样的类型,其中 T
可以是 int
、double
等。显然它们是用方括号访问的。
现在我需要为这两种情况创建一个模板。 Eigen
有很多矩阵类型(MatrixXd
、SparseMatrix
等),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
}
所以我想创建一个函数,将文本文件中的数据读取到各种矩阵中。
这首先是一个 Eigen
矩阵,您可以在其中访问带括号的元素。
例如。 mat(1,2)
。第二种是像 vector<vector<T>
这样的类型,其中 T
可以是 int
、double
等。显然它们是用方括号访问的。
现在我需要为这两种情况创建一个模板。 Eigen
有很多矩阵类型(MatrixXd
、SparseMatrix
等),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
}