Q:

Automatic conversion of function arguments between related template classes

Suppose I have a pair of related templates, and I want to automatically convert arguments to some function from one of them to the other. How can I achieve that?
template<int a> struct bar;

template<int a, int b> struct foo {
  operator bar<a> const (); // operator-based conversion
};

template<int a> struct bar : public foo<a, a> {
  bar() { }
  template<int b> bar(const foo<a, b>&) { } // constructor-based conversion
};

template<int a, int b> foo<a, b>::operator bar<a> const () { return bar<a>(); }

template<int a> void f(bar<a> x, bar<a> y) { }

int main() {
  bar<1> x;
  foo<1, 2> y;
  f(x, y);
}

To this, gcc 4.8.3 says:
template argument deduction/substitution failed: ‘foo<1, 2>’ is not derived from ‘bar<a>’

The intention would be that the second argument to f gets converted from foo<1,2> to bar<1> via some code which I control. But apparently neither the templated conversion constructor nor the non-templated cast operator work for this case. Is there any idiom I can use to make this work?

A:

Template argument deduction requires exact matches (as Xeo points out in the comments, a single standard conversion sequence (Clause 4) will be applied, if needed), and user defined conversions are not considered. So it fails to deduce the template argument a from the second argument to f() (which is of type foo<1,2>). One way around this is to turn the second parameter type into a non-deduced context. Then a will be deduced from the first argument alone, and your code will compile.
#include <functional>
#include <memory>

template<typename T>
struct identity
{
  using type = T;
};

template<int a> struct bar;

template<int a, int b> struct foo {
  operator bar<a> const (); // operator-based conversion
};

template<int a> struct bar : public foo<a, a> {
  bar() { }
  template<int b> bar(const foo<a, b>&) { } // constructor-based conversion
};

template<int a, int b> foo<a, b>::operator bar<a> const () { return bar<a>(); }

template<int a> void f(bar<a> x, typename identity<bar<a>>::type y) { }
//                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
int main() {
  bar<1> x;
  foo<1, 2> y;
  f(x, y);
}

Live demo

