使用模板进行隐式类型转换

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

问题描述

限时送ChatGPT账号..

我有一个模板class 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>&)
{
    return A<m>(0);
}

但是当我打电话时:

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

我希望将 int 隐式转换为 A,但编译器会抛出错误.

I would like int to be implicitly converted to A, but compilers throws error.

是否有任何优雅的方法可以在不使用以下解决方案的情况下启用隐式转换:

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

  • a + A(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::maxstd::min 函数:

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

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

类型推导会推导出模板中的T;min( T const &, T const & ) 对于第一个参数是 unsigned 但对于第二个参数是 int 它们不同,编译器将丢弃它模板函数.

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.

答案 中提出的解决方案是使用该语言的一项功能,让您可以定义非会员好友类定义中的函数.模板的优点在于,对于模板的每个(不同)实例化,编译器将在命名空间级别创建一个免费的非模板函数,该函数具有通过替换朋友声明中实例化的真实类型获得的签名:

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.

此外,一种不同类型的魔法继续查找,因为这样定义的函数只能通过依赖参数的查找找到除非它也在命名空间级别声明,在我们的例子中不能以通用的方式完成.这意味着好坏,取决于你想如何考虑......

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).

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

上一篇:C++ 模板构造函数 下一篇:在编译时确定类型是否为 STL 容器

相关文章

最新文章