Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
792 views
in Technique[技术] by (71.8m points)

c++ - 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...