使用模板的C ++隐式类型转换 [英] C++ implicit type conversion with template

查看:116
本文介绍了使用模板的C ++隐式类型转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模板 A类

template <unsigned int m>
class A
{
public:
    A(int) {}
};

其中包含 int 的构造函数。我有一个操作:

Which has a constructor from int. And I have an operation:

template<unsigned int m>
A<m> operator+(const A<m>&, const A<m>&)
{
    retrun A<m>(0);
}

但是当我调用:

A<3> a(4);
A<3> b = a + 5;
A<3> c = 5 + a;

我想要隐式转换 int

有没有任何优雅的方式来启用隐式转换,而不使用如下解决方案:

Is there any elegant way to enable implicit conversion without using such solutions as:


  • a + A (5)

  • + 3(a,5)

  • a + A<m>(5)
  • operator+<3>(a, 5)

推荐答案

解决方案已显示在此答案中。现在,更多的问题...

The solution is already shown in this answer. Now, more about the problem...

代码中的问题是如何执行重载分辨率。当模板函数被考虑用于重载解析时,编译器将对参数执行类型推导,并且得到与调用匹配的类型替换,否则它不能应用该模板,将其从潜在候选集中移除并继续。此时的问题是类型推导只推导出精确匹配(可能有额外的const / volatile限定)。因为匹配是准确的,编译器不会使用任何转换(再次,除了cv)。

The problem in your code is how overload resolution is performed. When a template function is considered for overload resolution the compiler will perform type deduction on the arguments and come up with a type substitution that matches the call or else it fails to apply that template, removes it from the set of potential candidates and continues over. The problem at this point is that type deduction only deduces exact matches (with possible extra const/volatile qualification). Because the matching is exact, the compiler will not use any conversion (again, other than cv).

最简单的例子发生在 std :: max std :: min 函数:

The simplest example of this happens with std::max and std::min functions:

unsigned int i = 0;
std::min( i, 10 );    // Error! 

类型扣除将推导出 template< typename T&对于第一个参数,但是 int c $ c>第二个它们不同,编译器将丢弃此模板函数。

Type deduction will deduce the T in template <typename T> min( T const &, T const & ) to be unsigned for the first argument but int for the second they differ and the compiler will discard this template function.

answer 正在使用语言的一个特性,使您能够在类定义中定义非成员友好函数。模板的优点在于,对于模板的每个(不同的)实例化,编译器将在命名空间级别创建一个自由的非模板函数,其具有通过在朋友声明中替换实例化的真实类型而获得的签名:

The solution proposed in the answer is using a feature of the language that enables you to define a non-member friend function inside the class definition. The advantage with templates is that for every (different) instantiation of the template, the compiler will create a free non-template function at namespace level that has the signature obtained by substituting the real types of the instantiation in the friend declaration:

template <typename T>
class test {
    friend test operator+( test const & lhs, test const & rhs ) {  // [1]
        return test();
    }
}
test<int> t;                                                       // [2]



在上面的例子中,编译器允许你添加朋友的定义函数在类范围内[1]。然后,当在[2]中实例化模板时,编译器将生成一个自由函数:

In the example above, the compiler allows you to add the definition of the friend function inside the class scope at [1]. Then when you instantiate the template in [2], the compiler will generate a free function:

test<int> operator+( test<int> const & lhs, test<int> const & rhs ) { 
   return test<int>();
}

函数总是定义它不是(这不同于模板类成员函数,按需实例化)。

The function is defined always, whether you use it or not (this differs to the template class member functions, that are instantiated on demand).

这里的魔法有多个方面。第一部分是一般您为每个和所有实例化类型定义非模板函数,因此您可以获得通用性,同时重载分辨率的优点是能够使用此函数当参数不是完美匹配时。

The magic here has multiple sides to it. The first part is that it generically you are defining non-template functions for each and all of the instantiated types, so you gain genericity and at the same time the advantage of overload resolution being able to use this function when the arguments are not perfect matches.

因为它是一个非模板函数,编译器能够调用这两个参数的隐式转换,你会得到你期望的行为。

Because it is a non-template function, the compiler is able to call implicit conversions on both arguments, and you will get your expected behavior.

此外,不同类型的 magic 继续使用lookup,因为这样定义的函数只能通过参数依赖查找找到除非也在命名空间级别声明,在我们的情况下不能以通用方式完成。这意味着好的或坏的,取决于你想要怎么考虑...

Additionally, a different type of magic goes on with lookup, as the function so defined can only be found by argument dependent lookup unless it is also declared at namespace level, which in our case cannot be done in a generic way. The implication of this might be good or bad, depending on how you want to consider it...

因为它只能通过ADL找到,所以不会被考虑除非至少有一个参数已经是期望的类型(即它永远不会被用来执行两个参数的转换)。缺点是,除非你实际上正在调用,否则不可能引用函数,这意味着你不能获取函数指针。

Because it can only be found by ADL it will not be considered unless at least one of the arguments is already of the desired type (i.e. it will never be used performing conversions to both arguments). The downside is that it is impossible to refer to the function unless you are actually calling it, and that means that you cannot obtain a function pointer.

(有关模板友谊的详情,请此处,但请注意,在此特殊情况下,所有其他版本都无法执行隐式转换)。

(More on template friendship here, but note that in this particular case, all the other variants will fail to perform implicit conversions).

这篇关于使用模板的C ++隐式类型转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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