Implicit conversion to pattern

My example below shows that implicit conversions from types without templates to template types will not work as easily as those associated only with types without templates. Is there any way to make them work nonetheless?

Example:

struct point;

template<unsigned d> struct vec {
  vec() { }
  // ...
};

template<> struct vec<2> {
  vec() { }
  vec(const point& p) { /* ... */ } // Conversion constructor
  // ...
};

struct point {
  operator vec<2>() { return vec<2>(/* ... */); } // Conversion operator
};

template<unsigned d> vec<d> foo(vec<d> a, vec<d> b) {
  return vec<d>(/* ... */);
}

template<unsigned d1, unsigned d2>
vec<d1 + d2> bar(vec<d1> a, vec<d2> b) {
  return vec<d1 + d2>(/* ... */);
}

int main(int argc, char** argv) {
  point p1, p2;
  vec<2> v2;
  vec<3> v3;
  foo(v2, p1);
  foo(p2, v2);
  foo(p1, p2);
  bar(v3, p1);
}

Can I autocopy this code from pointto vec<2>?

I know that I can overload fooand bar, to resolve the arguments point, delegating the implementation vecusing an explicit conversion. But to do this for all combinations of parameters will become tedious, especially for functions with many such parameters. Therefore, I do not need solutions where I have to duplicate the code for each combination of parameters of each function.

, , . , gcc 4.7.1 no matching function call, , , ‘point’ is not derived from ‘vec<d>’.

+5
1

point vec<2>, foo(v1,p1) foo, vec<2>, . , , foo(const vec<2> &,const vec<2> &), .

, , , , point . ( , ).

, , , - :

template <typename T>
struct make_vec
{ };

template <unsigned d>
struct make_vec<vec<d>>
{
  static constexpr unsigned dim = d;
  using type = vec<dim>;

  static const type &from(const type &v)
  { return v; }
};

template <>
struct make_vec<point>
{
  static constexpr unsigned dim = 2;
  using type = vec<dim>;

  static type from(const point &p)
  { return type(p); }
};

template <typename T>
typename make_vec<typename std::decay<T>::type>::type make_vec_from(T&& arg)
{ return make_vec<typename std::decay<T>::type>::from(std::forward<T>(arg)); }

foo bar ( , vec<d>, make_vec, , vec<d>):

namespace detail {
  /* Your original implementation of foo. */
  template<unsigned d> vec<d> foo(vec<d>, vec<d>) {
    return vec<d>(/* ... */);
  }
}

/* Templated version of foo that calls the conversion functions (which do
   nothing if the argument is already a vec<d>), and then calls the
   foo() function defined above. */
template <typename T, typename... Ts>
typename make_vec<typename std::decay<T>::type>::type foo(T&& arg, Ts&&... args)
{ return detail::foo(make_vec_from(arg),make_vec_from(args)...); }

bar , vec<d1+d2+d3...>. , :

template <typename... Ts>
struct dsum {
  static constexpr unsigned value = 0;
};

template <typename T, typename... Ts>
struct dsum<T,Ts...> {
  static constexpr unsigned value = make_vec<typename std::decay<T>::type>::dim + dsum<Ts...>::value;
};

bar() vec<dsum<T,Ts...>::value>.

: http://liveworkspace.org/code/nZJYu$11

, , .

+8

All Articles