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

时间:2019-04-12 13:01:02

标签: c++ templates

说我想要两个正交类型A和B,以便我可以写

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

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

#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;

旁注:找不到与此主题相关的任何问题,如果找到一个问题,请链接!

3 个答案:

答案 0 :(得分:3)

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

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); }

答案 1 :(得分:2)

您可以创建将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 );
};

答案 2 :(得分:1)

不幸的是,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);