具有特征的 C++ 可变参数模板,使用参数列表重载函数会产生意想不到的结果
C++ Varaidic Tempate with Eigen, overloading functions with parameter list gives unexpected result
我一直在 Eigen 中测试 C++ 模板,在使用模板和模板化参数列表进行开发时遇到了一个问题。
根据以下示例,所有调用都会打印 "Function 2" - 即使第 3 次和第 4 次调用与原型完全匹配。由于歧义,模板化参数列表似乎优先。
现在有趣的部分是,这只发生在矩阵被包裹在 "Eigen::MatrixBase" 中时,如果我直接发送矩阵,这不是问题。但这对于正在使用的表达式模板来说并不是最佳选择。
有人可以解释一下使用 MatrixBase 时出现这种情况的原因吗?有什么解决方法?
我知道给一个函数起一个不同的名字就可以了,但是这样函数就会失去通用性。有没有更好的修复方法?
感谢您的宝贵时间!
显示效果的最小示例:
typedef Eigen::Matrix<float, 2, 2> QType;
typedef Eigen::Matrix<float, 1, 1> UType;
template <typename... ParamsType>
void fun(const Eigen::MatrixBase<QType> &Q,
const Eigen::MatrixBase<UType> &U,
const ParamsType & ...params)
{
cout << "Function 1" << endl;
}
template <typename... ParamsType>
void fun(const Eigen::MatrixBase<QType> &Q,
const ParamsType & ...params)
{
cout << "Function 2" << endl;
}
template <typename... ParamsType>
void fun2(const QType &Q,
const UType &U,
const ParamsType & ...params)
{
cout << "Function 1" << endl;
}
template <typename... ParamsType>
void fun2(const QType &Q,
const ParamsType & ...params)
{
cout << "Function 2" << endl;
}
int main(int argc, char *argv[])
{
QType Q = QType::Random();
UType U = UType::Random();
int param = 0;
fun(Q);
fun(Q, param);
fun(Q, U);
fun(Q, U, param);
fun2(Q);
fun2(Q, param);
fun2(Q, U);
fun2(Q, U, param);
return 0;
}
输出:
Function 2
Function 2
Function 2
Function 2
Function 2
Function 2
Function 1
Function 1
原因是UType
和MatrixBase<UType>
不一样,而是继承了它。这意味着将 U
作为可变参数传递更接近函数头(抱歉无法引用标准中的相应部分)。请参阅此简化示例,它也说明了差异:
#include <iostream>
class A {};
class B {};
class C : public A { };
class D : public B { };
template<typename... P>
void fun(const A&, const B&, const P & ...p)
{
std::cout << "funAB\n";
}
template<typename... P>
void fun(const A&, const P & ...)
{
std::cout << "funAP\n";
}
int main()
{
A a;
B b;
C c;
D d;
fun(a,b); // funAB
fun(c,d); // funAP, because d only inherits from B
}
如果您明确希望在传递 UType
时调用 "Function1",只需将其写为参数(如在您的 fun2
实现中那样)。
我一直在 Eigen 中测试 C++ 模板,在使用模板和模板化参数列表进行开发时遇到了一个问题。 根据以下示例,所有调用都会打印 "Function 2" - 即使第 3 次和第 4 次调用与原型完全匹配。由于歧义,模板化参数列表似乎优先。 现在有趣的部分是,这只发生在矩阵被包裹在 "Eigen::MatrixBase" 中时,如果我直接发送矩阵,这不是问题。但这对于正在使用的表达式模板来说并不是最佳选择。
有人可以解释一下使用 MatrixBase 时出现这种情况的原因吗?有什么解决方法? 我知道给一个函数起一个不同的名字就可以了,但是这样函数就会失去通用性。有没有更好的修复方法?
感谢您的宝贵时间!
显示效果的最小示例:
typedef Eigen::Matrix<float, 2, 2> QType;
typedef Eigen::Matrix<float, 1, 1> UType;
template <typename... ParamsType>
void fun(const Eigen::MatrixBase<QType> &Q,
const Eigen::MatrixBase<UType> &U,
const ParamsType & ...params)
{
cout << "Function 1" << endl;
}
template <typename... ParamsType>
void fun(const Eigen::MatrixBase<QType> &Q,
const ParamsType & ...params)
{
cout << "Function 2" << endl;
}
template <typename... ParamsType>
void fun2(const QType &Q,
const UType &U,
const ParamsType & ...params)
{
cout << "Function 1" << endl;
}
template <typename... ParamsType>
void fun2(const QType &Q,
const ParamsType & ...params)
{
cout << "Function 2" << endl;
}
int main(int argc, char *argv[])
{
QType Q = QType::Random();
UType U = UType::Random();
int param = 0;
fun(Q);
fun(Q, param);
fun(Q, U);
fun(Q, U, param);
fun2(Q);
fun2(Q, param);
fun2(Q, U);
fun2(Q, U, param);
return 0;
}
输出:
Function 2
Function 2
Function 2
Function 2
Function 2
Function 2
Function 1
Function 1
原因是UType
和MatrixBase<UType>
不一样,而是继承了它。这意味着将 U
作为可变参数传递更接近函数头(抱歉无法引用标准中的相应部分)。请参阅此简化示例,它也说明了差异:
#include <iostream>
class A {};
class B {};
class C : public A { };
class D : public B { };
template<typename... P>
void fun(const A&, const B&, const P & ...p)
{
std::cout << "funAB\n";
}
template<typename... P>
void fun(const A&, const P & ...)
{
std::cout << "funAP\n";
}
int main()
{
A a;
B b;
C c;
D d;
fun(a,b); // funAB
fun(c,d); // funAP, because d only inherits from B
}
如果您明确希望在传递 UType
时调用 "Function1",只需将其写为参数(如在您的 fun2
实现中那样)。