如何确定从类模板继承的模板参数的基础模板类型

How to Determine Underlying Template Type of Template Parameter That Inherits From a Class Template?

本文关键字:参数 类型 继承 何确定      更新时间:2023-10-16

这个问题以前可能被问过,也被回答过,但我还没能找到它的搜索词。下面是一些代码来显示我的问题(打算作为伪代码……如果需要,请澄清)。

图片.h:

template <class T>
class Image
{
    public:
        // Return pointer to data.
        T* GetValues(); 
        std::vector<T> data_;
};
template <class T>
T* Image<T>::GetValues()
{
    return &data_[0];
}

SpecialImage.h

class SpecialImage : public Image<float>
{
}

Stack.h

template<class T>
class Stack
{
    public:
        void NegateAllImageValues();
        std::vector<T> stackOfImages_;
};
template <class T>
void Stack::NegateAllImageValues()
{
    for(int i = 0; i < stackOfImages_.size(); ++i)
    {
        // Type L should be float if T=SpecialImage, but how to get?
        L* imageValues = stackOfImages_.at(i).GetValues(); 
        // Loop over values and multiply by -1.0.
    }
}

main.cpp

{
    // Create stack of SpecialImages.
    Stack<SpecialImage> myStack; 
    // Create special image and add some data.
    SpecialImage mySpecialImage; 
    mySpecialImage.data_.push_back(1.0f);
    mySpecialImage.data_.push_back(2.0f);
    mySpecialImage.data_.push_back(3.0f);
    // Add special image to stack.
    myStack.stackOfImages_.push_back(mySpecialImage);
    // Negate all values in all SpecialImages in the stack.
    myStack.NegateAllImageValues();
}

我的问题是如何知道Stack::NegateAllImageValues中的类型L?我意识到我可以编写一个方法Image::NegateAllValues,并从Stack::NegateAllImageValues调用它,但我想知道是否有办法在Stack级别获得类型L。我想我可以在函数Stack::NegateAllImageValues中添加一个额外的模板参数,比如

template <class T, class L>
void Stack::NegateAllImageValues()
{
    for(int i = 0; i < stackOfImages_.size(); ++i)
    {
        // Type L should be float if T=SpecialImage, but how to get?
        L* imageValues = stackOfImages_.at(i).GetValues(); 
        // Loop over values and multiply by -1.0.
    }
}

但是类型L不被强制与图像的底层模板类型相匹配。

这里是否存在固有的设计缺陷?有没有一种方法可以在堆栈级别获得类型L?

实现这一点的经典方法是在Image类中放入一个typedef/别名,类似

template <typename T>
class Image {
public:
    typedef T value_type;
    // Other stuff
};

然后在稍后的Stack::NegateAllImageValues()方法中,您可以说

template <class T>
void Stack::NegateAllImageValues()
{
    for(int i = 0; i < stackOfImages_.size(); ++i)
    {
        typename T::value_type* imageValues = stackOfImages_.at(i).GetValues(); 
        // Loop over values and multiply by -1.0.
    }
}

这些类型的typedef基本上被标准库中的每个模板类使用:例如,std::vector<T>包含(除其他外)成员typedef value_type,它是T的别名。

C++11和更新版本中的一个替代方案是使用auto,例如:

template <class T>
void Stack::NegateAllImageValues()
{
    for(int i = 0; i < stackOfImages_.size(); ++i)
    {
        auto* imageValues = stackOfImages_.at(i).GetValues(); 
        // Loop over values and multiply by -1.0.
    }
}

[普通的autoauto*一样好用,但我更喜欢后者,因为它清楚地表明您期望的是指针类型。]

最后,在C++11中,您可以使用decltype来获得GetValues():的返回类型

template <class T>
void Stack::NegateAllImageValues()
{
    for(int i = 0; i < stackOfImages_.size(); ++i)
    {
        using value_type = decltype(stackOfImages_.at(i).GetValues());
        value_type imageValues = stackOfImages_.at(i).GetValues(); 
        // Loop over values and multiply by -1.0.
    }
}

尽管这并不能真正让你在auto上有所收获。