【问题标题】:Automatic conversion of function arguments between related template classes相关模板类之间函数参数的自动转换
【发布时间】:2014-07-29 16:46:01
【问题描述】:

假设我有一对相关的模板,我想自动将参数转换为某个函数,从其中一个到另一个。我怎样才能做到这一点?

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);
}

对此,gcc 4.8.3 说:

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

目的是通过我控制的一些代码将f 的第二个参数从foo&lt;1,2&gt; 转换为bar&lt;1&gt;。但显然,模板化转换构造函数和非模板化转换运算符都不适用于这种情况。有什么成语可以用来完成这项工作吗?

【问题讨论】:

  • 我认为这是因为void f() 是一个模板函数;隐式参数转换对于模板函数是非法的。试试void f(bar&lt;1&gt; x, bar&lt;1&gt; y)

标签: c++ templates c++11 type-conversion


【解决方案1】:

模板参数推导需要完全匹配(正如 Xeo 在comments 中指出的那样,如果需要,将应用单个标准转换序列(第 4 条)),并且不考虑用户定义的转换。所以它无法从第二个参数推导出模板参数af()(类型为foo&lt;1,2&gt;)。解决此问题的一种方法是将第二个参数类型转换为非推导上下文。然后a 将仅从第一个参数推导出来,您的代码将编译。

#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

【讨论】:

  • 现场演示足够小,您可以将其内联到您的帖子中。
  • “精确”仅适用于单个标准转换序列。
【解决方案2】:

当您对两个或多个参数执行模板参数推导时,两个参数必须完全匹配,通过限定转换或通过基类转换 (14.8.2.1p4 [temp.deduct.call])。

您可以使用类型转换禁止对一个参数进行参数推导:

template<class T> struct identity { using type = T; };
template<class T> using identity_t = typename identity<T>::type;
template<int a> void f(bar<a> x, identity_t<bar<a>> y) { }

【讨论】:

  • 执行单个标准转换序列。
  • @Xeo 我很确定 [temp.deduct.call] 适用;标准转换序列在哪里适合?
  • 啊,它不完全是 SCS,但基本上表现得像一个。我认为 p4 中的子点处理资格转换,然后左值到右值适用。积分促销等不适合,因为没有促销目标。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-21
  • 1970-01-01
  • 2011-10-25
  • 2021-09-26
  • 2016-03-16
  • 2013-04-12
相关资源
最近更新 更多