First there is a vector with a size 20. We assign random numbers from 0 to 100 to the vector. Then, using the template function, we find the total, mean, median, and standard deviation of this vector's elements. The code is as follows and the screen output is below.
#include <numeric>
#include <cmath>
#include <algorithm>
#include <functional>
#include <vector>
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
template<int N, class T>
T nthPower(T x) {
T ret = x;
for (int i=1; i < N; ++i) {
ret *= x;
}
return ret;
}
template<class T, int N>
struct SumDiffNthPower {
SumDiffNthPower(T x) : mean_(x) { };
T operator( )(T sum, T current) {
return sum + nthPower<N>(current - mean_);
}
T mean_;
};
template<class T, int N, class Iter_T>
T nthMoment(Iter_T first, Iter_T last, T mean) {
size_t cnt = distance(first, last);
return accumulate(first, last, T( ), SumDiffNthPower<T, N>(mean)) / cnt;
}
template<class T, class Iter_T>
T computeVariance(Iter_T first, Iter_T last, T mean) {
return nthMoment<T, 2>(first, last, mean);
}
template<class T, class Iter_T>
T computeStdDev(Iter_T first, Iter_T last, T mean) {
return sqrt(computeVariance(first, last, mean));
}
template<class T, class Iter_T>
void computeStats(Iter_T first, Iter_T last, T& sum, T& mean,
T& var, T& std_dev)
{
size_t cnt = distance(first, last);
sum = accumulate(first, last, T( ));
mean = sum / cnt;
var = computeVariance(first, last, mean);
std_dev = sqrt(var);
}
int RandomNumber () { return (std::rand()%100); }
int main(int argc, char **argv) {
std::srand ( unsigned ( std::time(0) ) );
vector<int> v(20);
std::generate (v.begin(), v.end(), RandomNumber);
double sum, mean, var, dev;
computeStats(v.begin( ), v.end( ), sum, mean, var, dev);
cout << "count = " << v.size( ) << "\n";
cout << "sum = " << sum << "\n";
cout << "mean = " << mean << "\n";
cout << "variance = " << var << "\n";
cout << "standard deviation = " << dev << "\n";
cout << endl;
}
Output is:
count = 20
sum = 789
mean = 39.45
variance = 888.448
standard deviation = 29.8068
How can I change the parameters?
I don't want to use this style.
template<class T, class Iter_T>
T computeVariance(Iter_T first, Iter_T last, T mean) {
return nthMoment<T, 2>(first, last, mean);
}
I want to use this way to calculate things.
template<class T, class T2>
T computeVariance(vector<T2> &vec, T mean)
{
...
}
All function should be like this. How can I do?
In main function how can I use generate function for copying vector and How can I send the addresses of the arguments
std::generate (v.begin(), v.end(), RandomNumber);
computeStats(v.begin( ), v.end( ), sum, mean, var, dev);
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
template <int N, class T>
T nthPower(T x) {
T ret = x;
for (int i = 1; i < N; ++i) {
ret *= x;
}
return ret;
}
template <class T, int N>
struct SumDiffNthPower {
SumDiffNthPower(T x) : mean_(x){};
T operator()(T sum, T current) {
return sum + nthPower<N>(current - mean_);
}
T mean_;
};
template <class T, int N, class T2>
T nthMoment(vector<T2> &vec, T mean) {
size_t cnt = vec.size();
return accumulate(vec.begin(), vec.end(), T(), SumDiffNthPower<T, N>(mean)) / cnt;
}
template <class T, class T2>
T computeVariance(vector<T2> &vec, T mean) {
return nthMoment<T, 2>(vec, mean);
}
template <class T, class T2>
T computeStdDev(vector<T2> &vec, T mean) {
return sqrt(computeVariance(vec, mean));
}
template <class T, class T2>
void computeStats(vector<T2> &vec, T &sum, T &mean, T &var, T &std_dev) {
size_t cnt = vec.size();
sum = accumulate(vec.begin(), vec.end(), T());
mean = sum / cnt;
var = computeVariance(vec, mean);
std_dev = sqrt(var);
}
int RandomNumber() { return (std::rand() % 100); }
int main(int argc, char **argv) {
std::srand(unsigned(std::time(0)));
vector<int> v(20);
std::generate(v.begin(), v.end(), RandomNumber);
double sum, mean, var, dev;
computeStats(v, sum, mean, var, dev);
cout << "count = " << v.size() << "\n";
cout << "sum = " << sum << "\n";
cout << "mean = " << mean << "\n";
cout << "variance = " << var << "\n";
cout << "standard deviation = " << dev << "\n";
cout << endl;
return 0;
}
I hope this will work. PS: I didn't got your passing by argument thing. Explain it in comments, maybe I can help with you that.
you can have
template<class T, class T2>
T computeVariance(vector<T2> &vec, T mean)
{
return nthMoment<T, 2>(vec.begin(), vec.end(), mean);
}
Related
template<typename T,int nSize>
T Sum(T (&parr)[nSize])
{
T sum=0;
for(int i = 0; i < nSize ;++i)
{
sum += parr[i];
}
return sum;
}
int _tmain(int argc, _TCHAR* argv[])
{
int nArr[] = {1,2,3,4};
int nSum = Sum(nArr);
std::cout<<"Sum :"<<nSum;
}
Can std::vector be used instead of array.Or can array be replaced by any of the stl containers?
Can std::vector be used instead of array.Or can array be replaced by
any of the stl containers?
No. It is not possible as they are different in their types. But you can generalize the given function in the following way.
Make a template function taking the begin and end iterators of the container. Then using std::accumulate, sum the elements up, which will work for any sequence containers as well as the arrays:
Following is an example code: (See live online)
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <numeric> // std::accumulate
#include <iterator> // std::iterator_traits, std::cbegin, std::cend
template<typename Iterator>
constexpr auto Sum(Iterator begin, const Iterator end) -> typename std::iterator_traits<Iterator>::value_type
{
using RetType = typename std::iterator_traits<Iterator>::value_type;
return std::accumulate(begin, end, RetType{});
}
int main()
{
int nArr[] = { 1,2,3,4 };
std::vector<int> vec{ 1,2,3,4 };
std::list<int> list{ 1,2,3,4 };
// now you can
std::cout << "Sum of array: " << Sum(std::cbegin(nArr), std::cend(nArr)) << "\n";
std::cout << "Sum of vec: " << Sum(std::cbegin(vec), std::cend(vec)) << "\n";
std::cout << "Sum of list: " << Sum(std::cbegin(list), std::cend(list)) << "\n";
}
Output:
Sum of array: 10
Sum of vec: 10
Sum of list: 10
template<typename T, int nSize>
T sum(std::array<T, nSize> const&);
would be the equivalent signature for std::array. As you see, signature differs already. Trying to do the same for std::vector is bound to fail:
template<typename T, int nSize>
T sum(std::vector<T> const&);
How would you be able to know at compile time already how many elements will reside in the vector??? You simply cannot. Even if you specified nSize in code explicitly, e. g. sum<std::vector<int>, 7>, the function then would always try to iterate over exactly seven elements, resulting in undefined behaviour if there are less and not counting the surplus ones if there are more...
The typical way to go is using begin and end iterators, just as the standard library does, too, for all of its algorithms:
template <typename Iterator>
auto sum(Iterator begin, Iterator end) -> std::remove_reference_t<decltype(*begin)>
{
using type = decltype(sum(begin, end)); // just not wanting to repeat all
// that remove_reference stuff...
type s = type();
for( ; begin != end; ++begin)
{
s += *begin;
}
return s;
}
You additionally could, based on this function, provide a generic overload for arbitrary containers then:
template <typename Container>
auto sum(Container const& c)
{
using std::begin;
using std::end;
return sum(begin(c), end(c));
}
If your compiler supports C++ 17 then you can write a single function with using if constexpr statement.
For example
#include <iostream>
#include <vector>
template<typename T>
auto Sum( const T &container )
{
if constexpr( std::is_array_v<std::remove_reference_t<T>> )
{
std::remove_extent_t<T> sum = 0;
for ( const auto &item : container )
{
sum += item;
}
return sum;
}
else
{
typename T::value_type sum = 0;
for ( const auto &item : container )
{
sum += item;
}
return sum;
}
}
int main()
{
int nArr[] = { 1, 2, 3, 4 };
int nSum = Sum( nArr );
std::cout << "Sum :"<<nSum << '\n';;
std::vector<int> v = { 1, 2, 3, 4 };
nSum = Sum( v );
std::cout << "Sum :"<<nSum << '\n';;
}
The program output is
Sum :10
Sum :10
However it is better to split the function into two functions: one for arrays and other for standard containers.
#include <iostream>
#include <vector>
template<typename T, size_t N>
auto Sum( const T ( &a )[N] )
{
T sum = 0;
for ( const auto &item : a )
{
sum += item;
}
return sum;
}
template<typename T>
auto Sum( const T &container )
{
typename T::value_type sum = 0;
for ( const auto &item : container )
{
sum += item;
}
return sum;
}
int main()
{
int nArr[] = { 1, 2, 3, 4 };
int nSum = Sum( nArr );
std::cout << "Sum :"<<nSum << '\n';;
std::vector<int> v = { 1, 2, 3, 4 };
nSum = Sum( v );
std::cout << "Sum :"<<nSum << '\n';;
}
I have a container (Vector) of some arbitrary type and i want to get a vector with indices of the n greatest (or smallest) elements.
Is there a standard way to do so?
This is exactly the topic of one of the guru of the week http://www.gotw.ca/gotw/073.htm
I am reporting the preferred solution, however, I strongly recommend you to read the article (and the blog in general), it is really good.
#include <vector>
#include <map>
#include <algorithm>
namespace Solution3
{
template<class T>
struct CompareDeref
{
bool operator()( const T& a, const T& b ) const
{ return *a < *b; }
};
template<class T, class U>
struct Pair2nd
{
const U& operator()( const std::pair<T,U>& a ) const
{ return a.second; }
};
template<class IterIn, class IterOut>
void sort_idxtbl( IterIn first, IterIn last, IterOut out )
{
std::multimap<IterIn, int, CompareDeref<IterIn> > v;
for( int i=0; first != last; ++i, ++first )
v.insert( std::make_pair( first, i ) );
std::transform( v.begin(), v.end(), out,
Pair2nd<IterIn const,int>() );
}
}
#include <iostream>
int main()
{
int ai[10] = { 15,12,13,14,18,11,10,17,16,19 };
std::cout << "#################" << std::endl;
std::vector<int> aidxtbl( 10 );
// use another namespace name to test a different solution
Solution3::sort_idxtbl( ai, ai+10, aidxtbl.begin() );
for( int i=0; i<10; ++i )
std::cout << "i=" << i
<< ", aidxtbl[i]=" << aidxtbl[i]
<< ", ai[aidxtbl[i]]=" << ai[aidxtbl[i]]
<< std::endl;
std::cout << "#################" << std::endl;
}
I have below data structure,
typedef vector< tuple<int,int,int> > vector_tuple;
In vector i am storing tuple<value,count,position>
I want to sort my vector based on count, If count is same then based on position sort the vector.
structure ordering
{
bool ordering()(....)
{
return /// ?
}
};
int main()
{
std::vector<int> v1{1,1,1,6,6,5,4,4,5,5,5};
std::vector<int> v2(v1);
vector_tuple vt;
std::tuple<int,int,int> t1;
std::vector<int>::iterator iter;
int sizev=v1.size();
for(int i=0; i < sizev ; i++)
{
auto countnu = count(begin(v2),end(v2),v1[i]);
if(countnu > 0)
{
v2.erase(std::remove(begin(v2),end(v2),v1[i]),end(v2));
auto t = std::make_tuple(v1[i], countnu, i);
vt.push_back(t);
}
}
sort(begin(vt),end(vt),ordering(get<1>vt); // I need to sort based on count and if count is same, sort based on position.
for (int i=0; i < vt.size(); i++)
{
cout << get<0>(vt[i]) << " " ;
cout << get<1>(vt[i]) << " " ;
cout << get<2>(vt[i]) << " \n" ;
}
}
Your compare method should look like:
auto ordering = [](const std::tuple<int, int, int>& lhs,
const std::tuple<int, int, int>& rhs) {
return std::tie(std::get<1>(lhs), std::get<2>(lhs))
< std::tie(std::get<1>(rhs), std::get<2>(rhs));
};
std::sort(std::begin(vt), std::end(vt), ordering);
All credit to Jarod42 for the std::tie answer.
Now let's make it generic by creating a variadic template predicate:
template<std::size_t...Is>
struct tuple_parts_ascending
{
template<class...Ts>
static auto sort_order(const std::tuple<Ts...>& t)
{
return std::tie(std::get<Is>(t)...);
}
template<class...Ts>
bool operator()(const std::tuple<Ts...>& l,
const std::tuple<Ts...>& r) const
{
return sort_order(l) < sort_order(r);
}
};
which we can invoke thus:
sort(begin(vt),end(vt),tuple_parts_ascending<1,2>());
Full Code:
#include <vector>
#include <algorithm>
#include <tuple>
#include <iostream>
using namespace std;
typedef std::vector< std::tuple<int,int,int> > vector_tuple;
template<std::size_t...Is>
struct tuple_parts_ascending
{
template<class...Ts>
static auto sort_order(const std::tuple<Ts...>& t)
{
return std::tie(std::get<Is>(t)...);
}
template<class...Ts>
bool operator()(const std::tuple<Ts...>& l,
const std::tuple<Ts...>& r) const
{
return sort_order(l) < sort_order(r);
}
};
int main()
{
std::vector<int> v1{1,1,1,6,6,5,4,4,5,5,5};
std::vector<int> v2(v1);
vector_tuple vt;
std::tuple<int,int,int> t1;
std::vector<int>::iterator iter;
int sizev=v1.size();
for(int i=0; i < sizev ; i++)
{
auto countnu = count(begin(v2),end(v2),v1[i]);
if(countnu > 0)
{
v2.erase(std::remove(begin(v2),end(v2),v1[i]),end(v2));
auto t = std::make_tuple(v1[i], countnu, i);
vt.push_back(t);
}
}
sort(begin(vt),end(vt),tuple_parts_ascending<1,2>());
for (int i=0; i < vt.size(); i++)
{
cout << get<0>(vt[i]) << " " ;
cout << get<1>(vt[i]) << " " ;
cout << get<2>(vt[i]) << " \n" ;
}
}
Expected results:
6 2 3
4 2 6
1 3 0
5 4 5
Going further, we could make this operation a little more generic and 'library-worthy' by allowing the ordering predicate and the indices to be passed as parameters (this solution required c++14):
namespace detail {
template<class Pred, std::size_t...Is>
struct order_by_parts
{
constexpr
order_by_parts(Pred&& pred)
: _pred(std::move(pred))
{}
template<class...Ts>
constexpr
static auto sort_order(const std::tuple<Ts...>& t)
{
return std::tie(std::get<Is>(t)...);
}
template<class...Ts>
constexpr
bool operator()(const std::tuple<Ts...>& l,
const std::tuple<Ts...>& r) const
{
return _pred(sort_order(l), sort_order(r));
}
private:
Pred _pred;
};
}
template<class Pred, size_t...Is>
constexpr
auto order_by_parts(Pred&& pred, std::index_sequence<Is...>)
{
using pred_type = std::decay_t<Pred>;
using functor_type = detail::order_by_parts<pred_type, Is...>;
return functor_type(std::forward<Pred>(pred));
}
Now we can sort like so:
sort(begin(vt),end(vt),
order_by_parts(std::less<>(), // use predicate less<void>
std::index_sequence<1, 2>())); // pack indices into a sequence
Using lambdas:
std::sort(std::begin(vt),std::end(vt),[](const auto& l,const auto& r){
if(std::get<1>(l)== std::get<1>(r)){
return std::get<2>(l) < std::get<2>(r);
}
return std::get<1>(l) < std::get<1>(r);
});
Inspired by Antony Williams' "C++ Concurrency in Action" I took a closer look at his parallel version of std::accumulate. I copied its code from the book and added some output for debugging purposes and this is what I ended up with:
#include <algorithm>
#include <future>
#include <iostream>
#include <thread>
template <typename Iterator, typename T>
struct accumulate_block
{
T operator()(Iterator first, Iterator last)
{
return std::accumulate(first, last, T());
}
};
template <typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{
const unsigned long length = std::distance(first, last);
if (!length) return init;
const unsigned long min_per_thread = 25;
const unsigned long max_threads = (length) / min_per_thread;
const unsigned long hardware_conc = std::thread::hardware_concurrency();
const unsigned long num_threads = std::min(hardware_conc != 0 ? hardware_conc : 2, max_threads);
const unsigned long block_size = length / num_threads;
std::vector<std::future<T>> futures(num_threads - 1);
std::vector<std::thread> threads(num_threads - 1);
Iterator block_start = first;
for (unsigned long i = 0; i < (num_threads - 1); ++i)
{
Iterator block_end = block_start;
std::advance(block_end, block_size);
std::packaged_task<T(Iterator, Iterator)> task{accumulate_block<Iterator, T>()};
futures[i] = task.get_future();
threads[i] = std::thread(std::move(task), block_start, block_end);
block_start = block_end;
}
T last_result = accumulate_block<Iterator, T>()(block_start, last);
for (auto& t : threads) t.join();
T result = init;
for (unsigned long i = 0; i < (num_threads - 1); ++i) {
result += futures[i].get();
}
result += last_result;
return result;
}
template <typename TimeT = std::chrono::microseconds>
struct measure
{
template <typename F, typename... Args>
static typename TimeT::rep execution(F func, Args&&... args)
{
using namespace std::chrono;
auto start = system_clock::now();
func(std::forward<Args>(args)...);
auto duration = duration_cast<TimeT>(system_clock::now() - start);
return duration.count();
}
};
template <typename T>
T parallel(const std::vector<T>& v)
{
return parallel_accumulate(v.begin(), v.end(), 0);
}
template <typename T>
T stdaccumulate(const std::vector<T>& v)
{
return std::accumulate(v.begin(), v.end(), 0);
}
int main()
{
constexpr unsigned int COUNT = 200000000;
std::vector<int> v(COUNT);
// optional randomising vector contents - std::accumulate also gives 0us
// but custom parallel accumulate gives longer times with randomised input
std::mt19937 mersenne_engine;
std::uniform_int_distribution<int> dist(1, 100);
auto gen = std::bind(dist, mersenne_engine);
std::generate(v.begin(), v.end(), gen);
std::fill(v.begin(), v.end(), 1);
auto v2 = v; // copy to work on the same data
std::cout << "starting ... " << '\n';
std::cout << "std::accumulate : \t" << measure<>::execution(stdaccumulate<int>, v) << "us" << '\n';
std::cout << "parallel: \t" << measure<>::execution(parallel<int>, v2) << "us" << '\n';
}
What is most interesting here is that almost always I will get 0 length time from std::accumulate.
Exemplar output:
starting ...
std::accumulate : 0us
parallel:
inside1 54us
inside2 81830us
inside3 89082us
89770us
What is the problem here?
http://cpp.sh/6jbt
As is the usual case with micro-benchmarking, you need to make sure that your code is actually doing something. You're doing an accumulate, but you're not actually storing the result anywhere or doing anything with it. So do you really need to have done any of the work anyway? The compiler just snipped out all that logic in the normal case. That's why you get 0.
Just change your code to actually ensure that work needs to be done. For example:
int s, s2;
std::cout << "starting ... " << '\n';
std::cout << "std::accumulate : \t"
<< measure<>::execution([&]{s = std::accumulate(v.begin(), v.end(), 0);})
<< "us\n";
std::cout << "parallel: \t"
<< measure<>::execution([&]{s2 = parallel_accumulate(v2.begin(), v2.end(), 0);})
<< "us\n";
std::cout << s << ',' << s2 << std::endl;
I'm having a problem getting the syntax right so if someone can help,please?
I have a timing function which take a function and its arguments as a parameters, but I'm not sure how should the call look like.
#include <iostream>
#include <iterator>
#include <random>
#include <vector>
#include<list>
#include<deque>
#include <algorithm>
#include <chrono>
#include <functional>
#include <sstream>
using namespace std;
using namespace std::chrono;
int global_SortType = 1;
template<class F, class A, typename T>
void times(F func, A arg, int n, T typeval) // call func(arg,n)
{
auto t1 = system_clock::now();
func(arg, n, typeval);
auto t2 = system_clock::now();
auto dms = duration_cast<milliseconds>(t2-t1);
cout << "f(x) took " << dms.count() << " milliseconds\n";
}
template<class T>
bool Greater(const T& v1, const T& v2)
{
return false;
}
bool Greater(const int& v1, const int& v2)
{
return v1 > v2;
}
bool Greater(const string& v1, const string& v2)
{
return strcmp(v1.c_str(), v2.c_str()) > 0;
}
template <class T>
struct GreaterThan: public std::binary_function<T, T, bool > {
bool operator () ( const T &ival, const T &newval ) const {
return Greater(ival, newval);
}
};
string random_gen(string& s)
{
string Result; // string which will contain the result
ostringstream convert; // stream used for the conversion
convert << rand();
return convert.str();
}
int random_gen(int& i){
default_random_engine re { std::random_device()() };
uniform_int_distribution<int> dist;
auto r= bind(dist,re);
int x =r();
return x;
}
template<class T>
void print(T& val)
{
}
void print(int& val)
{
cout << val << " ";
}
void print(string& val)
{
cout << val.c_str() << " ";
}
struct Record
{
int v;
string s;
Record(){}
Record(int iv, string ss): v(iv), s(ss)
{
}
};
Record random_gen(Record& r)
{
string stemp;
int i = 0;
return Record(random_gen(i), random_gen(stemp));
}
void print(Record& r)
{
cout<<"int="<<r.v<<" string=";
print(r.s);
}
bool Greater(const Record& r1, const Record& r2)
{
return global_SortType == 1 ? Greater(r1.v, r2.v) : Greater(r1.s, r2.s);
}
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
{
for(int i=0; i!=n; ++i) {
T gen = random_gen(valtype);
typename SequenceContainer::const_iterator it;
it=find_if(seq.begin(), seq.end(), std::bind2nd(GreaterThan<T>(), gen));
seq.insert(it, gen);
}
for(int i=n-1; i >=0; i--)
{
int gen = i;
if(i > 0)
gen = random_gen(i)%i;
typename SequenceContainer::const_iterator it=seq.begin();
for(int j = 0; j < gen; j++)
it++;
seq.erase(it);
}
}
int main()
{
int n=1000;
vector<int> v;
times(build_cont<std::vector<int>, int>, v, n, 0); // works
vector<string> sv;
string stemp = "";
times(build_cont<std::vector<string>, string>, sv, n, stemp); // works
global_SortType = 1;
vector<Record> rv;
Record rtemp(0, "sfds");
global_SortType = 2;
vector<Record> rsv;
Record rstemp(0, "sfds");
//This one desn't work and I'm not sure of the right syntax
times(build_cont<std::vector<Record>,Record>, sv, n, stemp);
return 0;
}
I'm getting this error
Non-const lvalue reference to type 'vector>' cannot bind to a value of unrelated type 'vector, allocator>>'
and it points to line
func(arg, n, typeval);
Inside this function:
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
You are using const_iterators rather than iterators to perform insertions and removals. You should change the definition of that function as follows:
template<typename SequenceContainer, class T>
void build_cont(SequenceContainer& seq, int n, T valtype)
{
for(int i=0; i!=n; ++i) {
T gen = random_gen(valtype);
typename SequenceContainer::iterator it;
// ^^^^^^^^
it=find_if(seq.begin(), seq.end(), std::bind2nd(GreaterThan<T>(), gen));
seq.insert(it, gen);
}
for(int i=n-1; i >=0; i--)
{
int gen = i;
if(i > 0)
gen = random_gen(i)%i;
typename SequenceContainer::iterator it=seq.begin();
// ^^^^^^^^
for(int j = 0; j < gen; j++)
it++;
seq.erase(it);
}
}
Also, you forgot to #include the <cstring> standard header, which contains the definition for the strcmp() function. You are using that function inside your Greater() function:
bool Greater(const string& v1, const string& v2)
{
return strcmp(v1.c_str(), v2.c_str()) > 0;
// ^^^^^^
// You need to #include <cstring> before calling this function
}
Moreover, you're invoking function times() with the wrong arguments (sv and stemp):
//This one desn't work and I'm not sure of the right sytax
times(build_cont<std::vector<Record>,Record>, rsv, n, rstemp);
// ^^^ ^^^^^^