使用可变参数模板改变模板参数

时间:2018-09-24 05:51:29

标签: c++ templates

如何分解以下代码,以便可以遍历T = doubleT = float?我已经阅读了可变参数模板,但是我 不了解如何在这种情况下应用它:

int main(int argc, char* argv[])
{
  ofstream writeDat;
  vector<int> nValues = {26,51,101,201};
  for(int i = 0; i< 4; i++){
    int N = nValues[i];
    typedef float T ;
    Matrix<T> a(N,N);
    Matrix<T> b(N,3);
    Matrix<T> x = Problem2<T>(N);
    string sFloat = "2/" + to_string(N) + "Float"+".dat";
    writeDat.open(sFloat);
    for(int i =1; i<N ; i++)
      writeDat << i << " " << x(i,1)<<endl;
    writeDat << N <<" "<< x(N,1)<< endl;
    writeDat.close();
  }
  for(int i = 0; i< 4; i++){
    int N = nValues[i];
    typedef double T ;
    Matrix<T> a(N,N);
    Matrix<T> b(N,3);
    Matrix<T> x = Problem2<T>(N);
    string s = "2/" + to_string(N) + "Double"+".dat";
    writeDat.open(s);
    for(int i =1; i<N ; i++)
      writeDat << i << " " << x(i,1)<<endl;
    writeDat << N <<" "<< x(N,1)<< endl;
    writeDat.close();
  }
  return 0;
}

2 个答案:

答案 0 :(得分:2)

使用可变参数扩展来调用包含重复逻辑的模板函数(或可变参数lambda):

#include<fstream>
#include<vector>

// the concept of a type wrapper
template<class T> struct type_wrapper;

// a model of type_wrapper for floats
template<>
struct type_wrapper<float> { 
    using type = float; 
    constexpr const char* name() const { return "Float"; }
};

// a model of type_wrapper for doubles
template<>
struct type_wrapper<double> { 
    using type = double; 
    constexpr const char* name() const { return "Double"; }
};


// call a template function once for each type wrapper in Ts...
template<class...Ts, class F>
auto for_each_type(F&& f)
{
    (f(type_wrapper<Ts>()),...);
}

template<class T>
struct Matrix
{
    Matrix(int, int);
    T& operator()(int, int);
};

template<class T> Matrix<T> Problem2(int);

int main()
{
    auto process = [](auto twrap) {
        using T = typename decltype(twrap)::type;
        std::ofstream writeDat;
        std::vector<int> nValues = {26,51,101,201};
        for(int i = 0; i< 4; i++){
            int N = nValues[i];
            Matrix<T> a(N,N);
            Matrix<T> b(N,3);
            Matrix<T> x = Problem2<T>(N);
            std::string sFloat = "2/" + std::to_string(N) + twrap.name() + ".dat";
            writeDat.open(sFloat);
            for(int i =1; i<N ; i++)
            writeDat << i << " " << x(i,1)<<std::endl;
            writeDat << N <<" "<< x(N,1)<< std::endl;
            writeDat.close();
        }
    };

    for_each_type<double, float>(process);
}

https://godbolt.org/z/w6g6AC

注意:

您可以像这样使for_each_type更可移植(即在c ++ 14上工作):

template<class...Ts, class F>
auto for_each_type(F&& f)
{
#if __cplusplus >= 201703L
    (f(type_wrapper<Ts>()),...);
#else
    using expand = int[];
    expand {
        0,
        (f(type_wrapper<Ts>()), 0)...
    };
#endif
}

答案 1 :(得分:1)

  

我已经阅读了可变参数模板,但我不知道该如何   在这种情况下应用它:

我相信@RichardHodges可以最充分地回答您的问题。作为参考,如果您希望能够比较variadic template(自C ++ 11起)或fold expression(自C ++ 17起)与{{3} }(这不是唯一的理由),那么您可以使用此代码段,例如:

#include <vector>
#include <fstream>

using namespace std;

// Undefined struct 
template <typename T> struct not_available;

// Non-specialized instantiations are not allowed, by using the undefined struct
template <typename T>
constexpr const char* type_string(){ return not_available<T>{}; }

// Specializing for `float`
template <>
constexpr const char* type_string<float>(){ return "Float"; }

// Specializing for `Double`
template <>
constexpr const char* type_string<double>(){ return "Double"; }

// Your classes
template<class T>
struct Matrix
{
    Matrix(int, int);
    T& operator()(int, int);
};

template<class T> Matrix<T> Problem2(int);

ofstream writeDat;
vector<int> nValues = {26,51,101,201};

// Your routine
template <typename T>
void func()
{  
    for(int i = 0; i< 4; i++){
    int N = nValues[i];    
    Matrix<T> a(N,N);
    Matrix<T> b(N,3);
    Matrix<T> x = Problem2<T>(N);
    string s = "2/" + to_string(N) + type_string<T>() +".dat";
    writeDat.open(s);
    for(int i =1; i<N ; i++)
      writeDat << i << " " << x(i,1)<<endl;
    writeDat << N <<" "<< x(N,1)<< endl;
    writeDat.close();
    }
}

int main(int argc, char* argv[])
{
    func<float>();
    func<double>();

    return 0;
}

注意:此代码段尝试尽可能地保留原始内容,但由于缺乏足够的理由,我不一定会建议使用全局变量,而不是function template而不是指代带有std::的名称。