隐式转换未发生 [英] Implicit conversion not happening

查看:64
本文介绍了隐式转换未发生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问的最后一个问题是我在尝试理解另一件事时偶然发现的……我也听不懂(不是我的一天)。

The last question I asked was something I stumbled upon when trying to understanding another thing... that I also can't understand (not my day).

这是一个很长的问题陈述,但至少我希望这个问题对许多人不仅对我个人有用。

This is quite a long question statement, but at least I hope this question might prove useful to many people and not only me.

我的代码如下:

template <typename T> class V;
template <typename T> class S;

template <typename T>
class V
{
public:
 T x;

 explicit V(const T & _x)
 :x(_x){}

 V(const S<T> & s)
 :x(s.x){}
};

template <typename T>
class S
{
public:
 T &x;

 explicit S(V<T> & v)
 :x(v.x)
 {}
};

template <typename T>
V<T> operator+(const V<T> & a, const V<T> & b)
{
 return V<T>(a.x + b.x);
}

int main()
{
 V<float> a(1);
 V<float> b(2);
 S<float> c( b );

 b = a + V<float>(c); // 1 -- compiles
 b = a + c;           // 2 -- fails
 b = c;               // 3 -- compiles

 return 0;
}

表达式1和3完美工作,而表达式2无法编译。

Expressions 1 and 3 work perfectly, while expression 2 does not compile.

如果我正确理解,会发生以下情况:

If I have understood properly, what happens is:

表达式1


  1. c 通过使用标准隐式转换为 const 转换顺序(仅由一个资格转换组成)。

  2. V (const S & s)<调用/ code>并生成一个临时 const V 对象(我们称其为 t )。它已经是const限定的,因为它是一个时间值。

  3. a 类似于 c 被转换为const。
  4. >
  5. operator +(const V< float& a,const V< float>& b)被调用,导致时间类型为我们可以称为 q const V< float>

  6. 默认 V< float> :: operator =(const& V< float>)被调用。

  1. c is is implicitly converted to const by using a standard conversion sequence (consisting on just one qualification conversion).
  2. V<float>(const S<T> & s) is called and a temporal the const V<float> object generated (let's call it t). It is already const-qualified because it is a temporal value.
  3. a is converted to const similarly to c.
  4. operator+(const V<float> & a, const V<float> & b) is called, resulting in a temporal of type const V<float> that we can call q.
  5. the default V<float>::operator=(const & V<float>) is called.

我可以到这里吗?如果我什至犯了最细微的错误,请告诉我,因为我正在尝试加深对隐式转换的理解...

Am I OK up to here? If I made even the most subtle mistake please, let me know, for I am trying to gain an understanding about implicit casting as deep as possible...

表达式3


  1. c 转换为 V< float> 。为此,我们有一个用户定义的转换序列:

    1.1。第一次标准转换:通过资格转换将 S< float> 转换为 const S< float>

    1.2。用户定义的转换: const S< float> 通过 V<转换为 V< float> 。 float>(const S< T& s)构造函数。

    1.3秒标准转换: V< float>

  2. 默认 V< float> :: operator =来转换为 const V< float> 。 (const& V< float>)被调用。

  1. c is converted to V<float>. For that, we have a user-defined conversion sequence:
    1.1. first standard conversion: S<float> to const S<float> via qualification conversion.
    1.2. user-defined conversion: const S<float> to V<float> via V<float>(const S<T> & s) constructor.
    1.3 second standard conversion: V<float> to const V<float> via qualification conversion.
  2. the default V<float>::operator=(const & V<float>) is called.

表达式2?

我不明白的是为什么第二个表达式有问题。为什么下面的序列不可能?

What I do not understand is why there is a problem with the second expression. Why is the following sequence not possible?


  1. c 转换为 V< float> ; 。为此,我们有一个用户定义的转换序列:

    1.1。初始标准转换:通过资格转换将 S< float> 转换为 const S< float>

    1.2。用户定义的转换: const S< float> 通过 V<转换为 V< float> 。 float>(const S< T& s)构造函数。

    1.3。最终标准转换:通过资格转换将 V< float> 转换为 const V< float>

  2. 步骤2至6与表达式1的情况相同。

  1. c is converted to V<float>. For that, we have a user-defined conversion sequence:
    1.1. initial standard conversion: S<float> to const S<float> via qualification conversion.
    1.2. user-defined conversion: const S<float> to V<float> via V<float>(const S<T> & s) constructor.
    1.3. final standard conversion: V<float> to const V<float> via qualification conversion.
  2. Steps 2 to 6 are the same as in case of expression 1.

阅读后我的C ++标准:嘿!也许问题在于13.3.3.1.2.3!',其中指出:

After reading the C++ standard I though: 'hey! maybe the problem has to to with 13.3.3.1.2.3!' which states:


如果用户定义的转换是由模板指定的转换函数,第二个标准转换序列必须具有完全匹配的等级。

If the user-defined conversion is specified by a template conversion function, the second standard conversion sequence must have exact match rank.

但这不是事实,因为资格转换具有完全匹配排名...

But that cannot be the case since the qualification conversion has exact match rank...

我真的不知道...

好吧,无论您有答案还是不,谢谢您的阅读:)

Well, whether you have the answer or not, thanks you for reading up to here :)

推荐答案

正如Edric所指出的,在模板参数推导过程中不考虑转换。在这里,您有两个可以从参数类型推导出模板参数T的上下文。

As Edric pointed out, conversions are not considered during template argument deduction. Here, you have two contexts where the template parameter T can be deduced from the type of the arguments:

template<class T>
v<T> operator+(V<T> const&, V<T> const&);
               ~~~~~~~~~~~  ~~~~~~~~~~~~

但是,您尝试使用左侧的 V< float> 和右侧的S来调用此函数模板。模板自变量推导会导致左侧T = float,并且右侧会出现错误,因为没有T,因此 V< T> 等于 S< T> 。可以认为这是模板参数推导失败,并且模板将被忽略。

But you try to invoke this function template with a V<float> on the left-hand side and an S on the right hand side. Template argument deduction results in T=float for the left hand side and you'll get an error for the right hand side because there is no T so that V<T> equals S<T>. This qualifies as a template argument deduction failure and the template is simply ignored.

如果您想允许转换,则算子+不应该是模板。有以下技巧:您可以将其定义为V的类模板内的内联朋友:

If you want to allow conversions your operator+ shouldn't be a template. There is the following trick: You can define it as an inline friend inside of the class template for V:

template<class T>
class V
{
public:
   V();
   V(S<T> const&); // <-- note: no explicit keyword here

   friend V<T> operator+(V<T> const& lhs, V<T> const& rhs) {
      ...
   }
};

这样,运算符不再是模板。因此,不需要模板参数推导,您的调用应该起作用。因为左侧是 V< float> ,所以可以通过ADL(依赖于参数的查找)找到运算符。右侧也可以正确转换为 V< float>

This way, the operator is not a template anymore. So, there is no need for template argument deduction and your invocation should work. The operator is found through ADL (argument dependent lookup) because the left-hand side is a V<float>. The right-hand side is properly converted to a V<float> as well.

为特定参数禁用模板参数推导。例如:

It is also possible to disable template argument deduction for a specific argument. For example:

template<class T>
struct id {typedef T type;};

template<class T>
T clip(
   typename id<T>::type min,
   T value,
   typename id<T>::type max )
{
   if (value<min) value=min;
   if (value>max) value=max;
   return value;
}

int main() {
   double x = 3.14;
   double y = clip(1,x,3); // works, T=double
}

即使第一个和最后一个的类型参数是一个int,在模板参数推导过程中不会考虑它们,因为 id< T> :: type 不是所谓的*可演绎上下文。因此,T仅根据第二个参数推导得出,这导致T = double且没有矛盾。

Even though the type of the first and last argument is an int, they are not considered during template argument deduction because id<T>::type is not a so-called *deducible context`. So, T is only deduced according to the second argument, which results in T=double with no contradictions.

这篇关于隐式转换未发生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆