带模板参数或typename

时间:2016-09-29 15:44:01

标签: c++ templates c++11 c++14

我正在创建一个包含数值数据向量的模板类(可以是int,float,double等)。它有一个操作,在数据上调用std::abs()。类似下面的代码。

#include <iostream>
#include <complex>
#include <vector>


template<typename T> class MyData
{
public:
   std::vector<T> data;
   MyData<T> my_abs() const;

};


template<typename T>
MyData<T> MyData<T>::my_abs() const
{
    MyData<T> output;
    output.data.reserve(data.size());
    typename std::vector<T>::const_iterator it;

    for (it = data.begin(); it != data.end(); it++)
    {
        output.data.push_back(std::abs(*it));
    }
    return output;
}


int main()
{
    MyData<double> A;
    A.data = std::vector<double>(10, -1.0);

    MyData<double> test = A.my_abs();

    for (auto el : test.data)
    {
        std::cout << el << std::endl;
    }
    return 0;
}

这适用于int,float,double等类型。我还希望能够将此类用于std::complex<double>

等类型

环顾四周,我发现我可以使用模板模板参数:

template<template<typename> class T, typename U> class MyData
{
public:
   std::vector<T<U>> data;
   MyData<U> my_abs() const;

};


template<template<typename> class T, typename U>
MyData<U> MyData<T<U>>::my_abs() const
{
    MyData<U> output;
    output.data.reserve(data.size());
    typename std::vector<T<U>>::const_iterator it;

    for (it = data.begin(); it != data.end(); it++)
    {
        output.data.push_back(std::abs(*it));
    }
    return output;
}

之前的代码不起作用,因为我的模板类需要两个参数,

error: wrong number of template arguments (1, should be 2)
MyData<U> abs() const;
       ^

理想情况下,我想要像以前的代码一样。其中my_abs()函数返回传递给我的模板的模板参数的类型。例如,如果我使用std::complex<double>,那么我的主要功能可能类似于:

int main()
{
    MyData<std::complex<double>> A;
    A.data = std::vector<std::complex<double>>(10, std::complex<double>(-1.0, -1.0));

    MyData<double> test = A.my_abs();

    for (auto el : test.data)
    {
        std::cout << el << std::endl;
    }
    return 0;
}

我不确定如何实现这一目标(或者甚至可以使用相同的模板类)。

3 个答案:

答案 0 :(得分:3)

您可以在声明中使用std::abs(T)的返回类型。

示例:

#include <iostream>
#include <complex>
#include <vector>
#include <cmath>
#include <utility>

template<typename T> class MyData
{
public:
   std::vector<T> data;
   using abs_type = decltype(std::abs(std::declval<T>()));
   auto my_abs() -> MyData<abs_type> const;
};

template<typename T>
auto MyData<T>::my_abs() -> MyData<abs_type> const
{
    MyData<abs_type> output;
    output.data.reserve(data.size());
    typename std::vector<T>::const_iterator it;

    for (it = data.begin(); it != data.end(); it++)
    {
        output.data.push_back(std::abs(*it));
    }
    return output;
}

int main()
{
    MyData<std::complex<double>> A;
    A.data = std::vector<std::complex<double>>(10, std::complex<double>(-1.0, -1.0));

    auto test = A.my_abs();

    for (auto el : test.data)
    {
        std::cout << el << std::endl;
    }
    return 0;
}

答案 1 :(得分:0)

你必须以这种方式写你的专业

template<template<typename> class T, typename U>
class MyData<T<U>> // <----- note the <T<U>>
{
public:
   std::vector<T<U>> data;
   MyData<U> my_abs() const;    
};

答案 2 :(得分:0)

你不需要一个类,模板函数就足够了。您可以为模板功能提供abs功能,例如

template<typename T, typename F> std::vector<T> my_abs(const std::vector<T> &in, F abs) {
    std::vector<T> out;
    for (auto &i: in) {
        out.push_back(abs(i));
    }

    return out;
}

将其称为

std::vector<int> res = my_abs(in, special_abs);

如果输入和输出的类型不同,则可以在TU上进行参数化。

正如@ Jarod42已经指出的那样,这对于像std::abs这样的重载函数不起作用。 你可以通过给lambda作为第二个参数来解决这个问题,例如

std::vector<int> res = my_abs(in, [](const auto& e) { return std::abs(e);});

另一种解决方法是通过强制转换为正确的类型

来明确选择适当的abs
std::vector<int> res = my_abs(in, static_cast<double(*)(double)>(std::abs));