简体   繁体   English

无法推断模板参数?

[英]could not deduce template argument?

I have the following class 我有以下课程

template<typename hi_t, typename lo_t>
struct int_t
{
hi_t hi;
lo_t lo;

int_t() : lo(0), hi(0) {}
int_t(int value) : lo(value), hi( value<0u? -1: 0 ) {}
int_t(unsigned value) : lo(value), hi( 0 ) {}

int_t& operator+=(const int_t& rhs)
{
    lo_t _lo = lo;

    lo += rhs.lo;
    hi += rhs.hi;
    hi += (int)(lo < _lo);

    return *this;
}

template<typename hi_t, typename lo_t>
inline friend int_t<hi_t, lo_t> operator+(const int_t<hi_t, lo_t>&, const int_t<hi_t, lo_t>&);
};

template<typename hi_t, typename lo_t>
int_t<hi_t, lo_t> operator+(const int_t<hi_t, lo_t>& lhs, const int_t<hi_t, lo_t>& rhs)
{ return int_t<hi_t, lo_t>(lhs) += rhs; }

when executing the following code 执行以下代码时

typedef int_t<long long, unsigned long long> int128;

int main()
{
    int128 i = 1024;
    i = i + 20;
}

the compiler produce the error: 编译器产生错误:

'int_t<hi_t,lo_t> operator +(const int_t<hi_t,lo_t> &,const int_t<hi_t,lo_t> &)' : could not deduce template argument for 'const int_t<hi_t,lo_t> &' from 'int'

when i put the code of template operator inside the class body - with removing the template line from the friend operator - it works, but with friend operator outside the class it can't deduce the operator. 当我把模板操作符的代码放在类体中时 - 从友元操作符中删除模板行 - 它可以工作,但是在类之外的朋友操作符它不能推断出操作符。 i thought when compiler generates code for this template operator the input parameters and return value will be of type int128 so it should have no problem from casting from int to that type. 我认为当编译器为此模板运算符生成代码时,输​​入参数和返回值将是int128类型,因此从int转换为该类型应该没有问题。

UPDATE UPDATE

if we define the friend operator inside the class as following the previous example works 如果我们在类中定义了friend运算符,就像前面的例子一样

template<typename hi_t, typename lo_t>
struct int_t
{
hi_t hi;
lo_t lo;

int_t() : lo(0), hi(0) {}
int_t(int value) : lo(value), hi( value<0u? -1: 0 ) {}
int_t(unsigned value) : lo(value), hi( 0 ) {}

int_t& operator+=(const int_t& rhs)
{
    lo_t _lo = lo;

    lo += rhs.lo;
    hi += rhs.hi;
    hi += (int)(lo < _lo);

    return *this;
}

friend int_t operator+(const int_t& lhs, const int_t& rhs)
{ return int_t(lhs) += rhs; }

};

the problem happens when trying to define the template operator outside the class 尝试在类外定义模板运算符时会发生问题

The code is trickier than it seems at first look. 代码比起初看起来更棘手。 The most tricky part is your declaration of a friend function. 最棘手的部分是你的朋友功能声明。 You should take a look at this answer regarding befriending a function from a template. 您应该看看有关从模板中与函数建立联系的答案 The short recommendation is that you remove the templated operator+ and you implement it as a non-template friend function inside the class declaration: 简短的建议是,你删除模板operator+你实现它的类声明的非模板友元函数:

template<typename hi_t, typename lo_t>
struct int_t
{
// ...
    friend int_t operator+(int_t lhs, const int_t& rhs ) {
        return lhs+=rhs;
    }
};

As of the particular error, it might not be that helpful, and it might even be confusing, but you can start by taking into account that a template will only be taken into account for operator overloading if after type deduction it is a perfect match (ie no conversion required). 截至特定错误,它可能没那么有用,甚至可能会让人感到困惑,但您可以首先考虑到,如果在类型推断后它是一个完美的匹配,模板只会被考虑用于运算符重载(即不需要转换)。 That means that int128_t + int will never be matched by a templated operator+ that has the same type for both left and right hand side, even if there is a conversion. 这意味着即使存在转换, int128_t + int也永远不会被模板化operator+匹配,左右两侧具有相同的类型。

The proposed solution above declares (and defines) a non-template function. 上面提出的解决方案声明(并定义)非模板函数。 Because it is defined inside the class, it will only be considered by Argument Dependent Lookup, and will thus only apply when one of the operators is a int_t , if it is found by ADL, then it will be picked up for overload resolution with the usual non-template rules, which means that the compiler is able to use any possible conversions to both the lhs or rhs (one of them must be an int_t instantiation if it was found by ADL, but it will convert the other). 因为它是在类中定义的,所以它只会被Argument Dependent Lookup考虑,因此只会在其中一个运算符是int_t ,如果ADL找到它,那么它将被选中以便重载解析通常的非模板规则,这意味着编译器能够对lhs或rhs使用任何可能的转换(如果ADL找到它们中的一个必须是int_t实例,但它将转换另一个)。

Turn on all your compiler warnings. 打开所有编译器警告。

You are using the same template parameter names in your friend declarations as in the template class itself, which is not good; 您在friend声明中使用与模板类本身中相同的模板参数名称,这是不好的; rename them. 重命名它们。 Here's one solution: Remove the out-of-line operator definition and make the inline definition this: 这是一个解决方案:删除外部运算符定义并进行内联定义:

template<typename H, typename L>
inline friend int_t operator+(const int_t & lhs, const int_t<H, L> & rhs)
{
  return int_t(lhs) += rhs;
}

Now, since your RHS is an arbitrary type, you have to mention the type: 现在,由于您的RHS是任意类型,您必须提及类型:

i = i + int128(20);

This is because there is no way to deduce parameters H,L from the integer 20 so that an appropriate conversion to int_t<H,L>(20) could be performed (see Nawaz's answer)! 这是因为无法从整数20推导出参数H,L ,因此可以执行到int_t<H,L>(20)的适当转换(参见Nawaz的答案)!


To take advantage of your conversion constructor from int , you can only operate on the same type, not a templated other type. 要利用int中的转换构造函数,您只能操作相同的类型,而不是模板化的其他类型。 To this end, add a non-template operator: 为此,添加一个非模板运算符:

int_t operator+(const int_t & rhs) const { return int_t(*this) += rhs; }

Now you can say i = i + 20; 现在你可以说i = i + 20; , using the int_t(int) constructor. ,使用int_t(int)构造函数。

Update: As the OP suggests, to allow for symmetric invocation ( i = 50 + i; ), and in order to only allow operations within a fixed type as David suggests, we should remove both the unary operator and the templated friend binary operator and instead just have a non-templated binary friend: 更新:正如OP建议的那样,为了允许对称调用( i = 50 + i; ),并且为了仅允许大卫建议的固定类型内的操作,我们应该删除一元运算符和模板化的朋友二元运算符而只是有一个非模板化的二元朋友:

friend int_t operator+(const int_t & lhs, const int_t & rhs) { return int_t(lhs) += rhs; }

That's a matter of design choice; 这是设计选择的问题; I would personally favour the final version. 我个人赞成最终版本。

Are you certain that operator+= should be a member template? 您确定operator+=应该是成员模板吗? Usually, you just 通常,你只是

inline friend int_t operator+(const int_t&, const int_t&) {...}

I'am not sure but maybe compiler needs template argument again 我不确定,但编译器可能需要再次使用模板参数

...
...
...

template<typename hi_t, typename lo_t>
int_t& operator+=(const int_t& rhs)
{
...
...
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM