варьировать аргументы шаблона, используя шаблоны - PullRequest
0 голосов
/ 24 сентября 2018

Как я могу вычислить следующий код, чтобы я мог выполнить цикл через T = double и T = 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 голосов
/ 24 сентября 2018

Используйте расширение variadic для вызова шаблонной функции (или лямбды variadic), содержащей вашу дублированную логику:

#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
}
0 голосов
/ 24 сентября 2018

Я читал о вариационных шаблонах, но я не понимаю, как его применять в этом случае:

Я считаю, что на ваш вопрос наиболее адекватно отвечает @RichardHodges .Для справки, в случае, если вы хотите иметь возможность сравнивать, делая это шаблон переменной (начиная с C ++ 11) или сложенное выражение (начиная с C ++ 17), если сделать это только с помощью шаблона функции (не для этого есть особая причина), то вы можете использовать этот фрагмент, например:

#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;
}

Примечание. Этот фрагмент кода максимально старается придерживаться вашего оригинала, но при отсутствии достаточно веской причины я бы не советовал использовать глобальные переменные , ни выбрав using namespace std вместо ссылки на имена с std::.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...