template class: ctor against function -> new C++ standard - c++

in this question:
template; Point<2, double>; Point<3, double>
Dennis and Michael noticed the unreasonable foolishly implemented constructor.
They were right, I didn't consider this at that moment.
But I found out that a constructor does not help very much for a template class like this one, instead a function is here much more convenient and safe
namespace point {
template < unsigned int dims, typename T >
struct Point {
T X[ dims ];
std::string str() {
std::stringstream s;
s << "{";
for ( int i = 0; i < dims; ++i ) {
s << " X" << i << ": " << X[ i ] << (( i < dims -1 )? " |": " ");
}
s << "}";
return s.str();
}
Point<dims, int> toint() {
Point<dims, int> ret;
std::copy( X, X+dims, ret.X );
return ret;
}
};
template < typename T >
Point< 2, T > Create( T X0, T X1 ) {
Point< 2, T > ret;
ret.X[ 0 ] = X0; ret.X[ 1 ] = X1;
return ret;
}
template < typename T >
Point< 3, T > Create( T X0, T X1, T X2 ) {
Point< 3, T > ret;
ret.X[ 0 ] = X0; ret.X[ 1 ] = X1; ret.X[ 2 ] = X2;
return ret;
}
template < typename T >
Point< 4, T > Create( T X0, T X1, T X2, T X3 ) {
Point< 4, T > ret;
ret.X[ 0 ] = X0; ret.X[ 1 ] = X1; ret.X[ 2 ] = X2; ret.X[ 3 ] = X3;
return ret;
}
};
int main( void ) {
using namespace point;
Point< 2, double > p2d = point::Create( 12.3, 34.5 );
Point< 3, double > p3d = point::Create( 12.3, 34.5, 56.7 );
Point< 4, double > p4d = point::Create( 12.3, 34.5, 56.7, 78.9 );
//Point< 3, double > p1d = point::Create( 12.3, 34.5 ); //no suitable user defined conversion exists
//Point< 3, int > p1i = p4d.toint(); //no suitable user defined conversion exists
Point< 2, int > p2i = p2d.toint();
Point< 3, int > p3i = p3d.toint();
Point< 4, int > p4i = p4d.toint();
std::cout << p2d.str() << std::endl;
std::cout << p3d.str() << std::endl;
std::cout << p4d.str() << std::endl;
std::cout << p2i.str() << std::endl;
std::cout << p3i.str() << std::endl;
std::cout << p4i.str() << std::endl;
char c;
std::cin >> c;
}
has the new C++ standard any new improvements, language features or simplifications regarding this aspect of ctor of a template class?
what do you think about the implementation of the combination of namespace, stuct and Create function?
many thanks in advance
Oops

Since the array is public, it is an option to omit the constructor and allow aggregate initialization (like boost::array<T, N> for example).
Point<2, int> p = {1, 2};
This is no worse than having to call a create function. (The create function might still be handy as a utility.)
In C++0x you will be able to have all sorts of coolness. For example, play with variadic templates, to have it checked at compile-time if the constructor is called with a right number of arguments. (The following could also check if the arguments ...U are all of type T, with some more metaprogramming fun, but it might not be absolutely necessary.)
//helper to copy variable amount of arguments into an array
namespace detail {
template <class T, class U>
void copy_variadic(T* p, U value)
{
*p = value;
}
template <class T, class First, class ...Rest>
void copy_variadic(T* p, First var, Rest ...args)
{
*p = var;
copy_variadic(++p, args...);
}
} //detail
template < unsigned int dims, typename T >
struct Point {
T X[ dims ];
Point() : X{}
{
}
template <class ...U>
Point(U... args) {
static_assert(sizeof...(args) == dims, "Too many or too few arguments to Point constructor");
detail::copy_variadic(X, args...);
}
//...
};
(Actually, with some modifications - perfect forwarding - copy_variadic would make a nice addition to my collection of variadic-template utilities, if someone doesn't come and point out a significantly better way.)

Yes, as Michael pointed out in his answer to your previous question, in C++0x you'll be able to use an initializer list to pass an arbitrary number of arguments to your ctor. In your case, the code would look something like:
template <int dims, class T>
class point {
T X[dims];
public:
point(std::initializer_list<T> const &init) {
std::copy(init.begin(), init.begin()+dims, X);
}
};
You could create a point object with this something like:
point<3, double> x{0.0, 0.0, 0.0};
Personally, I'm not sure I like the basic design very well though. In particular, I'd rather see X turned into an std::vector, and determine the number of dimensions strictly from the parameter list that was passed instead of having it as a template argument:
template <class T>
class point {
std::vector<T> X;
public:
point(std::initializer_list<T> init) {
std::copy(init.begin(), init.end(), std::back_inserter(X));
}
};
This does have some trade-offs though -- points with a different number of dimensions are still the same type. For example, it basically asserts that it's reasonable to assign a 2D point to a 3D point, or vice versa.

Related

C++: function that works with container and container of pointers as well

I think I'm facing something that I imagine is a quite common problem here.
I'd like to write a function that would be able to accept both a container (let's say std::vector) of objects, and a container of pointers to those objects.
What would be the proper way to do so?
Right now, I'm thinking
int sum(std::vector<int *> v)
{
int s = 0;
for (int * i : v) s += *i;
return s;
}
int sum(std::vector<int> v)
{
std::vector<int *> vp;
for (size_t i = 0; i < v.size(); ++i)
vp[i] = &v[i];
return sum(vp);
}
But it doesn't seem quite right, does it?
Consider the standard algorithm library where the problem you see has a solution.
Most algorithms have some default behavior but often allow you to customize that behavior via functor parameters.
For your specific case the algorithm of choice is std::accumulate.
Because this algorithm already exists I can restrict to a rather simplified illustration here:
#include <iostream>
#include <functional>
template <typename T,typename R,typename F = std::plus<>>
R sum(const std::vector<T>& v,R init,F f = std::plus<>{})
{
for (auto& e : v) init = f(init,e);
return init;
}
int main() {
std::vector<int> x{1,2,3,4};
std::vector<int*> y;
for (auto& e : x ) y.push_back(&e);
std::cout << sum(x,0) << "\n";
std::cout << sum(y,0,[](auto a, auto b) {return a + *b;});
}
std::plus is a functor that adds two values. Because the return type may differ from the vectors element type an additional template parameter R is used. Similar to std::accumulate this is deduced from the initial value passed as parameter. When adding int the default std::plus<> is fine. When adding integers pointed to by pointers, the functor can add the accumulator with the dereferenced vector element. As already mentioned this is just a simple toy example. In the above link you can find a possible implementation of std::accumulate (which uses iterators rather than the container directly).
With C++20 (or another ranges library), you can easily add or remove pointerness
template <std::ranges::range R, typename T>
concept range_of = requires std::same<std::ranges::range_value_t<R>, T>;
template <range_of<int *> IntPointers>
int sum_pointers(IntPointers int_pointers)
{
int result = 0;
for (int * p : int_pointers) result += *p;
return result;
}
void call_adding_pointer()
{
std::vector<int> v;
sum_pointers(v | std::ranges::views::transform([](int & i){ return &i; });
}
Or
template <range_of<int> Ints>
int sum(Ints ints)
{
int result = 0;
for (int i : ints) result += i;
return result;
}
void call_removing_pointer()
{
std::vector<int *> v;
sum(v | std::ranges::views::transform([](int * p){ return *p; });
}
You can make a function template, which behaves differently for pointer and non-pointer:
#include <iostream>
#include <vector>
using namespace std;
template <class T>
auto sum(const std::vector<T> &vec)
{
if constexpr (std::is_pointer_v<T>)
{
typename std::remove_pointer<T>::type sum = 0;
for (const auto & value : vec) sum += *value;
return sum;
}
if constexpr (!std::is_pointer_v<T>)
{
T sum = 0;
for (const auto & value : vec) sum += value;
return sum;
}
}
int main(){
std::vector<int> a{3, 4, 5, 8, 10};
std::vector<int*> b{&a[0], &a[1], &a[2], &a[3], &a[4]};
cout << sum(a) << endl;
cout << sum(b) << endl;
}
https://godbolt.org/z/sch3KovaK
You can move almost everything out of the if constexpr to reduce code duplication:
template <class T>
auto sum(const std::vector<T> &vec)
{
typename std::remove_pointer<T>::type sum = 0;
for (const auto & value : vec)
{
if constexpr (std::is_pointer_v<T>)
sum += *value;
if constexpr (!std::is_pointer_v<T>)
sum += value;
}
return sum;
}
https://godbolt.org/z/rvqK89sEK
Based on #mch solution:
template<typename T>
std::array<double, 3> center(const std::vector<T> & particles)
{
if (particles.empty())
return {0, 0, 0};
std::array<double, 3> cumsum = {0, 0, 0};
if constexpr (std::is_pointer_v<T>)
{
for (const auto p : particles)
{
cumsum[0] += p->getX();
cumsum[1] += p->getY();
cumsum[2] += p->getZ();
}
}
if constexpr (not std::is_pointer_v<T>)
{
for (const auto p : particles)
{
cumsum[0] += p.getX();
cumsum[1] += p.getY();
cumsum[2] += p.getZ();
}
}
double f = 1.0 / particles.size();
cumsum[0] *= f;
cumsum[1] *= f;
cumsum[2] *= f;
return cumsum;
}
Much cleaner and more efficient solution using std::invoke:
std::array<double, 3> centroid(const std::vector<T> & particles)
{
if (particles.empty())
return {0, 0, 0};
std::array<double, 3> cumsum{0.0, 0.0, 0.0};
for (auto && p : particles)
{
cumsum[0] += std::invoke(&topology::Particle::getX, p);
cumsum[1] += std::invoke(&topology::Particle::getY, p);
cumsum[2] += std::invoke(&topology::Particle::getZ, p);
}
double f = 1.0 / particles.size();
cumsum[0] *= f;
cumsum[1] *= f;
cumsum[2] *= f;
return cumsum;
}

Can I concatenate a std::tuple of Eigen::Vectors?

If I have a std::tuple of statically allocated Eigen::Vectors (from the popular Eigen library), for example
std::tuple<Eigen::Vector2f, Eigen::Vector3f, Eigen::Vector2f>
Is there a way I can turn this into a single Eigen::Vector7f (i.e., Eigen::Matrix<float, 7, 1>) of the three vectors concatenated? It feels like I should be able to do this at compile time, given that the sizes and types of everything are known.
You can write:
template<int R1, int R2, int R3>
auto foo(std::tuple<
Eigen::Matrix<float,R1,1>,
Eigen::Matrix<float,R2,1>,
Eigen::Matrix<float,R3,1> > t)
{
Eigen::Matrix<float,R1+R2+R3,1> res;
res.template block<R1,1>(0,0) = std::get<0>(t);
res.template block<R2,1>(R1,0) = std::get<1>(t);
res.template block<R3,1>(R1+R2,0) = std::get<2>(t);
return res;
}
int main() {
Eigen::Vector2f v1;
v1 << 1,2;
Eigen::Vector3f v2;
v2 << 3,4,5;
std::cout << foo(std::make_tuple(v1,v2,v1)) << std::endl;
as output:
1,2,3,4,5,1,2
Live demo
Below is more generic version taking multiple vectors as tuple components:
template<class RES, int ... R, size_t ... Indices>
void concatenateHelper(RES& res,
const std::tuple< Eigen::Matrix<float,R,1>... >& t,
std::index_sequence<Indices...>)
{
int idx = 0;
int fakeArray [] = {(res.template block<R,1>(idx,0) = std::get<Indices>(t),idx += R,0)...};
static_cast<void>(fakeArray);
}
template<int ... R>
auto concatenate(const std::tuple< Eigen::Matrix<float,R,1> ... >& t)
{
Eigen::Matrix<float, (R + ...),1> res;
concatenateHelper(res,t,std::make_index_sequence<sizeof...(R)>{});
return res;
}
Demo

c++ templates to represent polynomials

I am trying to use templates to represent simple polynomials like x^2 + 3x + 5. My idea is to represent them as sum of terms with each term having a coefficient and a power so e.g. x^2 has coeff=1 and power=2. I also want to be able to evaluate the polynomials for some x (they only have 1 unknown but in many places). So far I have:
struct PolyEnd{
double eval(double x){
return 0;
}
};
template <int coeff, int power, class Tail> struct Poly {
typedef Tail tt;
double eval(double x){
double curr = coeff * std::pow(x, power);
return curr; // has to call eval(x) on rest of the terms which are in the tail and return the sum with "curr"
}
};
int main()
{
double x = 2;
Poly<1,1,Poly<1,1,PolyEnd>> poly;
std::cout << poly.eval(x) << std::endl;
return 0;
}
However, I am stuck. Is what I am trying even possible? If so how can I make the recursive eval() calls work?
Yes, you can do that, you just need to call eval on the tail and since all the classes are state-less, you can just create an instance to call the member function on, on the spot:
struct PolyEnd{
double eval(double x){
return 0;
}
};
template <int coeff, int power, class Tail> struct Poly {
typedef Tail tt;
double eval(double x){
double curr = coeff * std::pow(x, power);
return curr + Tail{}.eval(x);
}
};
int main()
{
double x = 2;
Poly<1,1,Poly<1,1,PolyEnd>> poly;
std::cout << poly.eval(x) << std::endl;
return 0;
}
or if you make eval static, then you can call Tail::eval(x) directly.
I guess that you are experimenting with metaprogramming. Your question also made me excited, because i am also newbie in metaprogramming and I want to practise. #walnut's answer already accepted but there is no harm to share another implementation. I used some basic metaprogramming techniques.
I hope it will help you.
#include <cmath>
#include <iostream>
#include <string>
template<int Value>
struct coeff
{ };
template<int Value>
struct power
{ };
template<typename Coefficient, typename Power>
struct term;
template<int Coefficient , int Power>
struct term< coeff<Coefficient> , power<Power> >
{
inline double eval( double x ) const noexcept {
return Coefficient * std::pow( x , Power );
}
};
template<int Value>
using constant = term< coeff<Value> , power<1> >;
template<int Value>
using exponential = term< coeff<1> , power<Value> >;
template<typename... T>
struct polynomial
{
static_assert( sizeof...(T) == 0, "A polynomial can only be expressed in 'term's.");
[[nodiscard]] constexpr double eval( double ) const noexcept {
return 0;
}
[[nodiscard]] std::string to_string() const noexcept {
return std::string{};
}
};
template<int Coefficient, int Power, typename... Tail>
struct polynomial<term< coeff<Coefficient> , power<Power> >, Tail...>
: polynomial<Tail...>
{
[[nodiscard]] constexpr double eval( double x ) const noexcept {
return m_t.eval( x ) + polynomial<Tail...>::eval( x );
}
[[nodiscard]] std::string to_string(){
using namespace std;
using namespace std::string_literals;
return "("s + std::to_string( Coefficient ) +
string { "x^" } +
std::to_string( Power ) + ( sizeof...(Tail) == 0 ? ")" : ") + " ) +
polynomial<Tail...>::to_string();
}
private:
term< coeff<Coefficient> , power<Power> > m_t;
};
int main()
{
auto p1 = polynomial<term< coeff<1> , power<2> > ,
term< coeff<2> , power<4> > ,
term< coeff<2> , power<3> > ,
constant<3> ,
exponential<2> >{};
std::cout << "Polynomial is : " << p1.to_string() << std::endl;
std::cout << "f(2) : " << p1.eval( 2 ) << std::endl;
std::cout << "f(3) : " << p1.eval( 3 ) << std::endl;
return 0;
}
run online
Polynomial coefficients can be stored in std::array or std::vector(in case you define polynomial degree in runtime).
Then extend functionality with eval function.
template <unsigned N>
class Poly : public std::array<double, N> {
public:
template <typename... E>
Poly(E &&... e) : std::array<double, N>{{std::forward<E>(e)...}} {}
double eval(double x) {
double result = 0;
double exp = 1.;
for (auto it = this->rbegin(); it != this->rend(); ++it) {
result += exp * (*it);
exp *= x;
}
return result;
}
};
usage
double result = Poly<3>{3., 2., 1.}.eval(17);

Two Type Variadic Expansion

How does one do two type variadic expansion? Here is what I am trying to achieve:
#include <vector>
#include <iostream>
class test
{
public:
std::vector< std::pair< float, int > > vec;
template<typename... T1, typename... T2>
test( T1... one, T2... two )
{
(
[&](float first, int second)
{
vec.emplace_back( std::pair< float, int >( first, second ) );
std::cout << first << ", " << second << std::endl;
}( one, two ),
...
);
}
};
int main()
{
test t
{
1.f,
1,
2.f,
2,
3.f,
3
};
return 0;
}
test must be initialized exactly like in main. I'd like usage in the constructor of test to remain similar.
Here is a working concept with va_list. Unfortunately, I need to pass a count for the parameters or I need to pass a magic-number terminator (I opted for the magic-number terminator).
#include <cstdarg>
#include <iostream>
#include <vector>
constexpr int END_OBJECT = 890123; // magic number
class test {
public:
std::vector<std::pair<int, double>> vec;
enum { is_name, is_data, is_max };
test(char ch, ...) {
std::pair<int, double> buf;
va_list b;
va_start(b, ch);
for (int i = 0;; i++) {
auto is = i % is_max;
if (is == is_name) {
if ( (buf.first = va_arg(b, int)) == END_OBJECT )
break;
} else if (is == is_data) {
buf.second = va_arg(b, double);
vec.emplace_back(buf);
}
}
va_end(b);
std::cout << ch << std::endl;
for (auto &x : vec)
std::cout << '\t' << x.first << ", " << x.second << std::endl;
}
};
int main() {
test t
{
'x',
1,
2.0,
3,
4.0,
5,
6.0,
END_OBJECT
};
return 0;
}
I'd like a more modern version of this using pack-expansion.
It's funny how this is basically FizzBuzz with template arguments and it's actually a nice challenge.
The easiest way in C++14 I could come up with is to use std::index_sequence.
https://godbolt.org/z/dm3F9u
#include <vector>
#include <utility>
#include <tuple>
template <typename... TArgs, size_t... Is>
std::vector<std::pair<float, int>> pair_off(std::tuple<TArgs...> args, std::index_sequence<Is...>) {
return std::vector<std::pair<float, int>> { std::make_pair(std::get<(Is << 1)>(args), std::get<((Is << 1) + 1)>(args))... };
}
template <typename... TArgs>
std::vector<std::pair<float, int>> pair_off(TArgs&&... args) {
return pair_off(std::forward_as_tuple(std::forward<TArgs>(args)...), std::make_index_sequence<(sizeof...(TArgs) >> 1)>{});
}
std::vector<std::pair<float, int>> test() {
return pair_off(1.1f, 1, 2.2f, 2, 3.3f, 3);
}
Basically, first you pack the arguments into a tuple. Then you make an index sequence half the size of the argument list. Then you expand that index sequence, passing it into std::get.
What that does is the template equivalent of:
for (int i=0; i<list.size()/2; i++) {
output.push_back( std::make_pair(list[i*2], list[i*2+1]) );
}

template; operator (int)

regarding my Point struct already mentioned here:
template class: ctor against function -> new C++ standard
is there a chance to replace the function toint() with a cast-operator (int)?
namespace point {
template < unsigned int dims, typename T >
struct Point {
T X[ dims ];
//umm???
template < typename U >
Point< dims, U > operator U() const {
Point< dims, U > ret;
std::copy( X, X + dims, ret.X );
return ret;
}
//umm???
Point< dims, int > operator int() const {
Point<dims, int> ret;
std::copy( X, X + dims, ret.X );
return ret;
}
//OK
Point<dims, int> toint() {
Point<dims, int> ret;
std::copy( X, X + dims, ret.X );
return ret;
}
}; //struct Point
template < typename T >
Point< 2, T > Create( T X0, T X1 ) {
Point< 2, T > ret;
ret.X[ 0 ] = X0; ret.X[ 1 ] = X1;
return ret;
}
}; //namespace point
int main(void) {
using namespace point;
Point< 2, double > p2d = point::Create( 12.3, 34.5 );
Point< 2, int > p2i = (int)p2d; //äähhm???
std::cout << p2d.str() << std::endl;
char c; std::cin >> c;
return 0;
}
I think the problem is here that C++ cannot distinguish between different return types? many thanks in advance.
regards
Oops
The correct syntax is
operator int() const {
...
There's no need to have that extra return type when you overload the cast operator.
And when you say (int)x, the compiler really expects to get an int, not a Point<dims, int>. Probably you want a constructor instead.
template <typename U>
Point(const Point<dims, U>& other) { ... }