我有一个围绕std::vector
构建的模板类。看起来...
template <class T>
class Vector {
public:
std::vector<T> vec;
// Constructors...
// Operator overloads...
// Methods...
// etc.
};
我想创建一个派生模板类ComplexVector
,它将要求数据类型为std::complex<T>
,当然,我想重用我创建的方法,运算符重载等。在Vector
类中。
问题在于,似乎有两种方法可以做到这一点。
1)强制声明std::complex<T>
作为模板类型。
ComplexVector< std::complex<float> > myVec;
2)仅使用标量类型声明ComplexVector
,然后将std::complex
类型传递给Vector
构造函数。
ComplexVector<float> myVec;
// Constructor
ComplexVector<T>::ComplexVector() : Vector< std::complex<T> >
选项1在开发软件方面要简单得多,但对用户而言却很丑陋,而选项2对用户而言则更好。我想做第二种选择,但我担心它会如何工作。
如果我将std::vector<T>
传递给基类的构造函数,这是否只会改变构造函数的作用,还是整个模板将从类型T
变为std::complex< T >
?
如果不能全部转换为std::complex<T>
,这是否意味着我将不得不重载Vector
中的所有方法?
答案 0 :(得分:9)
如果您真的不想专门化,则可以像这样使用模板化typedef:
template <typename T>
using ComplexVector = Vector<std::complex<T>>;
然后用户可以使用ComplexVector<float>
,它将正确表示一个Vector<std::complex<T>>
。
这是一个非常简单的解决方案,无法完全满足您的需求。查看针对您的特定问题的以下解决方案。
如果您的目标是仅在T
为std::complex<U>
时更改特定方法,则您必须像这样从Vector
继承:
template <typename T>
class Vector
{
public:
bool is_complex() { return false; }
};
template <typename U>
class ComplexVector : Vector<std::complex<U>>
{
public:
bool is_complex() { return true; }
};
这还允许您添加仅适用于基于complex
的向量的方法。
ComplexVector
添加方法如果您想“增强” ComplexVector
,可以这样做:
#include <iostream>
#include <complex>
template <typename T>
class Vector
{
public:
bool is_complex() { return false; }
};
template <typename U>
class ComplexVector : Vector<std::complex<U>>
{
public:
bool is_complex() { return true; }
bool only_for_complex() { return true; } // Only in ComplexVector
};
int main() {
Vector<float> float_vec;
ComplexVector<float> complex_vec;
std::cout << "Is float_vec complex? " << float_vec.is_complex() << "\n";
std::cout << "Is complex_vec complex? " << complex_vec.is_complex() << "\n";
// The following line doesn't compile
// std::cout << "Is only_for_complex method in float_vec? " << float_vec.only_for_complex() << "\n";
std::cout << "Is only_for_complex method in complex_vec? " << complex_vec.only_for_complex() << "\n";
return 0;
}
使用一些模板,我们可以创建一个小助手来确定给定类型是否为ComplexVector
。如果想在模板繁重的环境中安全地调用特定方法,这可能会派上用场:
// For any type T, value is false.
template <typename T>
struct is_complex_vector
{
static const bool value = false;
};
// We specialize the struct so that, for any type U,
// passing ComplexVector<U> makes value true
template <>
template <typename U>
struct is_complex_vector<ComplexVector<U>>
{
static const bool value = true;
};
is_complex_vector<typeof(float_vec)>::value; // is false
is_complex_vector<typeof(complex_vec)>::value; // is true
Here is another small demo to demonstrate this behavior in practice
value
将在编译时确定。这可以允许您使用一些SFINAE技巧,以便更好地控制程序的流程。 (或者,如果您使用的是constexpr if,则可以使用C++17。)
答案 1 :(得分:5)
我认为您两次使用名称T感到困惑。这样看:
SERVICE_CONTROL_SESSIONCHANGE
答案 2 :(得分:2)
在原始q。的comments中,@ JimClay阐明了用例:他想使用fft
(快速傅立叶变换)之类的方法扩展复杂矢量。
当然可以从vector<T>
派生一个新类,例如ComplexVector<T>
并添加一个类似fft
的方法,但是我不建议这样做。详细原因如下。更好的选择是添加一个独立功能,例如
template<typename T>
vector<complex<T>> fft(const vector<complex<T>>&);
(为了方便阅读,该标签与using namespace std
一起使用。
以下是不使用派生模板类的原因:
vector<complex<T>>
v
的库函数。如果您滚动了自己的ComplexVector<T>
,则需要使用v
并将其转换为ComplexVector<T>
,然后再调用fft
。可以有效地完成 ,但是它要求用户在移动构造时要小心。 MyComplexVector<T>
和YourComplexVector<T>
。然后,想要一起使用我们的库的用户将需要使用MyComplexVector<T>
,将其转换为vector<T>
,然后再转换为YourComplexVector<T>
,然后再调用我的库。 [尽管在大多数情况下,第一次转换会隐式发生。] ComplexVector<T>
的语义,而每个C ++程序员都知道vector<T>
的行为。我已经大到可以在STL之前使用C ++了,并且一起使用库并不好玩!确实,库互操作性是引入标准string
,vector
等的主要原因之一。
请注意,如果您想实现高效的就地fft
,则需要一个右值引用版本:
template<typename T>
vector<complex<T>> fft(vector<complex<T>>&&);
答案 3 :(得分:0)
ComplexVector<std::complex<T> >
是多余的(您已经说过它是复数向量吧?)。
使用一般约定,您将到达:
class ComplexVector< T > : public Vector< std::complex<T> > {
public:
typedef std::complex<T> type;//for convenience, etc.
//...
}
添加Vector的特殊化(如某些建议),同时也不能直接进行继承,并且需要Vector<T>
-的重构(可能很困难),但是从根本上讲,它涉及将大部分/所有部分移动到新的通用基础上类。例如,如果您已经在Vector<T>
上工作,那可能是个好主意。