我正在处理代码并决定添加对标量类型的支持,以便能够在std::complex<double>
和普通double
之间切换。我已经编写了所有数字运算,并使用template <typename Scalar>
方法模板化。
我的“问题”是,对于复杂的情况,我需要提供一些额外的方法,在实际情况下没有意义,不能编码。
我之前的方法是创建一个基类模板,它实现了所有常见的东西。然后我有一个派生自这个基类的具体类,作为Scalar
模板参数std::complex<double>
。然后我有一种模板代理/虚拟类,它表现为double
版本和std::complex<double>
之间的切换。它看起来或多或少如下。
//base stuff
template<typename Scalar>
class NumberCruncherBase{
Scalar stuff1();
Scalar stuff2();
Scalar stuff3();
}
//inherit base stuff and extend it
class NumberCruncherComplex : public NumberCruncherBase< std::complex<double> >{
std::complex<double> extra_stuff1();
}
//switch proxy
template<typename Scalar>
class NumberCruncher : public NumberCruncherBase<Scalar> {}
//specialization for complex to explicitly derive from the extension
//in case of complex
template<>
class NumberCruncher< std::complex<double> > : public NumberCruncherBase< std::complex<double> > {}
令人惊讶的是,这种方法有点好用。您可以从NumberCruncher
派生或直接从具体的专业类型派生。也可以提供NumberCRuncherReal
用于同意,但这将是毫无意义的。
然而,这对代码来说有点麻烦,而且重复代码感觉很臃肿。我需要为Base类中的每一种ctor提供包装器。
我最近遇到boost
的{{1}}这似乎做了我需要的事情。但我无法让它发挥作用。我累了:
enable_if
这是类声明中的一行, const Matrix op_My( typename enable_if<boost::is_complex<Scalar> >::type* dummy = 0 ) { return g*H_sum_S[2]; };
说:
g++
我的问题是,这是一种很好的技术来实现我的目标吗?我该怎么写呢。我试着关注http://www.boost.org/doc/libs/1_54_0/libs/utility/enable_if.html。我使用gcc 4.8.1。
答案 0 :(得分:2)
你得到的具体错误是因为enable_if将bool作为第一个参数,但你传递了一个类型。
boost::is_complex<Scalar> // <- this is a type
要获得bool值(true / false),您需要写:
boost::is_complex<Scalar>::value // <- this is a bool value telling whether Scalar is complex
is_complex结构继承自true_type或false_type(取决于标量的类型),如果您想更详细地了解它的工作方式,请查找它们;)
您的代码还有其他问题。 enable_if需要依赖于在调用函数时首先知道的模板参数,而不是类模板参数。你可以这样做:
template<typename Scalar>
class matrix
{
//...
public:
// print function that will be called for a matrix of complex numbers
template<typename T=Scalar
, typename std::enable_if<boost::is_complex<T>::value,int>::type = 0
>
void print() const;
// print function that will be called for a matrix of non-complex numbers
template<typename T=Scalar
, typename std::enable_if<!boost::is_complex<T>::value,int>::type = 0
>
void print() const;
//...
};
这将产生一个&#34;开关&#34;根据类模板参数选择适当的类方法。我按惯例选择将enable_if放在模板参数中而不是函数签名中。我发现这是一个更通用的解决方案,而且更具可读性。
这是否是最好的&#34;提供此功能的方式,我不知道(不能在我的脑海中想到任何重大缺点),但它会做到这一点。希望它有所帮助:)
编辑08/11/13:
我使用特定类型的enable_if结构,因为它允许我在两个函数之间有一个enable_if开关,否则它将具有完全相同的签名。其中一个&#34;通常&#34;使用enable_if的方法是使用enable_if的结果作为模板参数的默认值,如下所示:
template<typename Scalar>
class matrix
{
//...
public:
// print function that will be called for a matrix of complex numbers
template<typename T=Scalar
, class = typename std::enable_if<boost::is_complex<T>::value>::type // enable_if is used to give default type for the class template
>
void print() const;
// print function that will be called for a matrix of non-complex numbers
template<typename T=Scalar
, class = typename std::enable_if<!boost::is_complex<T>::value>::type // same as above
>
void print() const; //<- this has same function signature as the above print()
// we get a compiler error
//...
};
编译器无法区分两个打印函数,因为它们都以相同的方式进行模板化,并具有相同的签名,因为它们都被视为
template<typename T, typename U>
void print() const;
在我的例子中,编译器不知道函数是如何被模板化的,因为这是由enable_if
的结果决定的。template<typename T, ?>
void print() const;
并且因此可以在调用函数并且对enable_if进行求值时首先看到函数签名。我按惯例选择了int,但你也可以使用void *:
typename std::enable_if<!boost::is_complex<T>::value,void*>::type = nullptr
使用void *而不是int,但不仅仅是void,因为我们不能有一个void非类型模板参数。
要执行您想要执行的操作,您需要在派生类中提供非模板化函数以覆盖基类中的抽象函数。为此,您可以使用间接并执行以下操作:
class matrix_base
{
public:
virtual void print() const = 0;
};
template<typename Scalar>
class matrix: matrix_base
{
//...
private:
// print function that will be called for a matrix of complex numbers
template<typename T=Scalar
, typename std::enable_if<boost::is_complex<T>::value,int>::type = 0
>
void print_impl() const;
// print function that will be called for a matrix of non-complex numbers
template<typename T=Scalar
, typename std::enable_if<!boost::is_complex<T>::value,int>::type = 0
>
void print_impl() const;
public:
// print function that will override abstract print in base class
void print() const { print_impl(); } // <- redirect to one of the print_impl() functions
//...
};
这种方法的缺点是你需要为每种可能的矩阵类型提供print_impl()实现,即你不能只为复数提供print_impl(),你还需要为非复数提供一个。
希望这能使事情变得更清楚:)