如何使模板化运算符推断出正确的返回类型

How can I make templated operator deduce correct return type?

本文关键字:返回类型 推断出 运算符 何使模      更新时间:2023-10-16

假设我想要两个正交类型 A 和 B,这样我就可以写

A a = b1 * b2; // b1,b2 of type B
B b = a1 * a2; // a1,a2 of type A

它们共享的数据是相同的,因此我尝试了一些基于策略的设计。一些代码:

#include <type_traits>
struct isA {};
struct isB {};
template<typename T>
struct myClass
{
    int _data;
    template<typename U>
    myClass<U> operator * ( const myClass<T>& other );
};
template<typename T>
template<typename U>
myClass<U> myClass<T>::operator * ( const myClass<T>& other )
{
    // just an idea, will not be needed if correct instanciation
    static_assert( std::is_same<U,T>::value, "cannot return same type" );
   // ... here, some code
}

int main()
{
    myClass<isA> a1,a2;
    myClass<isB> b = a1 * a2;
}

此操作失败,并显示:

main.cpp: In function 'int main()':
main.cpp:26:25: error: no match for 'operator*' (operand types are
'myClass<isA>' and 'myClass<isA>')
    myClass<isB> b = a1 * a2;
main.cpp:12:16: note: candidate: 'template<class U> myClass<U> myClass<T>::operator*(const myClass<T>&) [with U = U; T = isA]'
  myClass<U> operator * ( const myClass<T>& other );
 main.cpp:12:16: note:   template argument deduction/substitution failed:
 main.cpp:26:27: note:   couldn't deduce template parameter 'U'

我的理解是它失败了,因为它只是编译器用来生成实例化的函数参数,而不是返回类型。因此,编译器无法为运算符生成正确的实例化。

的问题(很简单(:我如何实现这个运算符?

这里不需要模板专用化,两种类型的行为相同(但其他函数 - 此处未显示 - 将针对每种类型具有特定的实现(。但我想强调一个你不能做的事实:A a = a1 * a2;

旁注:找不到有关此主题的任何问题,如果您找到,请链接!

您可以将其实现为两个(非模板(自由函数。如果实现完全相同,则可以指定共享实现的返回类型。

namespace detail
{
    template<typename Out, typename In>
    MyClass<Out> times( const MyClass<In> & lhs, const MyClass<In> & rhs)
    {
        // shared code here
    }
}
myClass<isA> operator * ( const myClass<isB>& lhs, const myClass<isB>& rhs )
{ return detail::times<isA>(lhs, rhs); }
myClass<isB> operator * ( const myClass<isA>& lhs, const myClass<isA>& rhs )
{ return detail::times<isB>(lhs, rhs); }

您可以创建一个将isA映射到isB并将isB映射到isA的特征。

namespace detail
{
    template<typename>
    struct myClassTraits;
    template<>
    struct myClassTraits<isA>
    {
        using other_type = isB;
    };
    template<>
    struct myClassTraits<isB>
    {
        using other_type = isA;
    };
}
template<typename T>
struct myClass
{
    int _data;
    using times_t = myClass<typename detail::myClassTraits<T>::other_type>;
    times_t operator * ( const myClass& other );
};

不幸的是,C++不使用返回类型来推断模板参数(其他一些语言可以做到这一点(,因此您无法对模板执行任何操作。

然而要使

A a = b1 * b2; // b1,b2 of type B

工作时,您可以实现隐式转换构造函数,以便首先由于乘法运算符获得类型 B,然后将其转换为A类型:

template <typename U>
myClass(const myClass<U>& other)  {} // copy conversion constructor
template <typename U>
myClass(myClass<U>&& other)  {} // move conversion constructor

因此

A a = b1 * b2;

将相当于

A a = A(b1 * b2);