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

Sea*_*ull 37 c++ templates type-conversion

我有一个模板 class A

template <unsigned int m>
class A
{
public:
    A(int) {}
};
Run Code Online (Sandbox Code Playgroud)

哪个有构造函数int.我有一个手术:

template<unsigned int m>
A<m> operator+(const A<m>&, const A<m>&)
{
    return A<m>(0);
}
Run Code Online (Sandbox Code Playgroud)

但是当我打电话时:

A<3> a(4);
A<3> b = a + 5;
A<3> c = 5 + a;
Run Code Online (Sandbox Code Playgroud)

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

有没有优雅的方法来启用隐式转换而不使用以下解决方案:

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

Dav*_*eas 37

解决方案已在此答案中显示.现在,更多关于这个问题......

代码中的问题是如何执行重载决策.当考虑模板函数进行重载解析时,编译器将对参数执行类型推导,并提出与调用匹配的类型替换,否则无法应用该模板,将其从潜在候选集中移除并继续.此时的问题是类型推导仅推导出完全匹配(可能具有额外的const/volatile限定).因为匹配是精确的,所以编译器不会使用任何转换(再次,除了cv).

最简单的例子就是std::maxstd::min函数:

unsigned int i = 0;
std::min( i, 10 );    // Error! 
Run Code Online (Sandbox Code Playgroud)

类型推导将推断的T template <typename T> min( T const &, T const & )unsigned为第一个参数,但int对于它们之间的区别,第二,编译器将丢弃该模板功能.

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

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

在上面的示例中,编译器允许您在[1]的类作用域内添加友元函数的定义.然后,当您在[2]中实例化模板时,编译器将生成一个自由函数:

test<int> operator+( test<int> const & lhs, test<int> const & rhs ) { 
   return test<int>();
}
Run Code Online (Sandbox Code Playgroud)

无论您是否使用该函数,都始终定义该函数(这与模板类成员函数不同,它们是按需实例化的).

这里的魔力有多方面.第一部分是,它通常为每个和所有实例化类型定义非模板函数,因此您获得了通用性,同时当参数不完美匹配时,重载解析的优势是能够使用此函数.

因为它是一个非模板函数,所以编译器能够在两个参数上调用隐式转换,并且您将获得预期的行为.

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

因为它只能由ADL找到,所以除非至少有一个参数已经是所需的类型(即它永远不会用于对两个参数执行转换),所以不会考虑它.缺点是除非你实际调用它,否则不可能引用该函数,这意味着你无法获得函数指针.

(有关模板友谊的更多信息,请注意,在此特定情况下,所有其他变体将无法执行隐式转换).


ipc*_*ipc 18

每次尝试使用模板提供操作员都需要至少一次第二次过载.但是你可以通过在类中定义运算符来避免这种情况:

template <unsigned int m>
class A
{
public:
  A(int) {}
  inline friend A operator+(const A& a, const A& b) { return A(0); }
};
Run Code Online (Sandbox Code Playgroud)

适用于两者,a+55+a.

  • @Seagull:在模板类`A`的定义中没有模板参数的`A`指的是'A <m>`而不仅仅是*any*`A <x>`. (2认同)