Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 无法推断模板参数?_C++_Templates - Fatal编程技术网

C++ 无法推断模板参数?

C++ 无法推断模板参数?,c++,templates,C++,Templates,我有以下课程 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

我有以下课程

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

当试图在类之外定义模板运算符时会出现问题,我不确定,但可能编译器需要再次使用模板参数

...
...
...

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

我不确定,但可能编译器需要再次使用模板参数

...
...
...

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

打开所有编译器警告

在朋友声明中使用的模板参数名称与模板类本身中使用的模板参数名称相同,这是不好的;重命名它们。这里有一个解决方案:删除越行运算符定义,并使内联定义如下:

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;
}
这是因为无法从整数20推断参数H,L,以便可以执行到int_t20的适当转换参见Nawaz的答案

要利用int的转换构造函数,只能对同一类型进行操作,而不能对模板化的其他类型进行操作。为此,请添加一个非模板运算符:

int_t operator+(const int_t & rhs) const { return int_t(*this) += rhs; }
现在你可以说i=i+20;,使用int_tint构造函数

更新:正如OP所建议的,为了允许对称调用i=50+i;,为了像David建议的那样只允许在固定类型内进行操作,我们应该删除一元运算符和模板化的友元二进制运算符,而只使用一个非模板化的二进制友元:

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

这是一个设计选择的问题;我个人倾向于最终版本。

打开所有编译器警告

在朋友声明中使用的模板参数名称与模板类本身中使用的模板参数名称相同,这是不好的;重命名它们。这里有一个解决方案:删除越行运算符定义,并使内联定义如下:

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;
}
这是因为无法从整数20推断参数H,L,以便可以执行到int_t20的适当转换参见Nawaz的答案

要利用int的转换构造函数,只能对同一类型进行操作,而不能对模板化的其他类型进行操作。为此,请添加一个非模板运算符:

int_t operator+(const int_t & rhs) const { return int_t(*this) += rhs; }
现在你可以说i=i+20;,使用int_tint构造函数

更新:正如OP所建议的,为了允许对称调用i=50+i;,为了像David建议的那样只允许在固定类型内进行操作,我们应该删除一元运算符和模板化的友元二进制运算符,而只使用一个非模板化的二进制友元:

friend int_t operator+(const int_t & lhs, const int_t & rhs) { return int_t(lhs) += rhs; }
这是一个设计选择的问题;我个人倾向于最终版本。

您确定operator+=应该是成员模板吗?通常,你只是

inline friend int_t operator+(const int_t&, const int_t&) {...}
您确定运算符+=应该是成员模板吗?通常,你只是

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

代码比乍看起来要复杂得多。最棘手的部分是友元函数的声明。您应该看看这个关于从模板友好化函数的例子。简短的建议是删除模板化运算符+,并将其作为类声明中的非模板友元函数实现:

template<typename hi_t, typename lo_t>
struct int_t
{
// ...
    friend int_t operator+(int_t lhs, const int_t& rhs ) {
        return lhs+=rhs;
    }
};
对于特定的错误,它可能没有那么大的帮助,甚至可能会让人困惑,但您可以首先考虑,如果在类型扣除后模板是完全匹配的,即不需要转换,则只有在运算符重载时才会考虑模板。这意味着int128_t+int永远不会被左右两侧类型相同的模板运算符+匹配,即使存在转换


上面提出的解决方案声明并定义了一个非模板函数。因为它是在类内部定义的,所以它只会被参数相关的查找所考虑,因此只会在其中一个运算符为int_t时应用,如果它是由ADL找到的,则将使用通常的非模板规则对其进行重载解析,这意味着编译器能够对lhs或rhs进行任何可能的转换。如果ADL发现其中一个必须是int_t实例化,但它会转换另一个。代码比乍看起来要复杂。最棘手的部分是友元函数的声明。您应该看看这个关于从模板友好化函数的例子。简短的建议是删除模板化运算符+,并将其作为类声明中的非模板友元函数实现:

template<typename hi_t, typename lo_t>
struct int_t
{
// ...
    friend int_t operator+(int_t lhs, const int_t& rhs ) {
        return lhs+=rhs;
    }
};
对于特定的错误,它可能没有那么大的帮助,甚至可能会让人困惑,但您可以首先考虑,如果在类型扣除后模板是完全匹配的,即不需要转换,则只有在运算符重载时才会考虑模板。这意味着int128_t+int永远不会被左右两侧类型相同的模板运算符+匹配,即使存在转换

上面提出的解决方案声明并定义了一个非模板函数。因为它是在类内部定义的,所以它只会被参数相关的查找考虑,因此只会在

运算符中的一个是int_t,如果ADL找到了它,那么它将使用通常的非模板规则进行重载解析,这意味着编译器能够使用到lhs或rhs的任何可能转换,如果ADL找到了,其中一个必须是int_t实例化,但它会转换另一个。

也不会在G++下编译,但错误不同;它抱怨friend函数的模板参数会影响类的模板参数。它也不能隐式地将20转换为int。此外,值<0u始终为false!我会尝试用我的风格重写它,也许我能抓住潜在的错误。@Frigo:friend声明有点偏离参考。例如,但我认为Muhammad的编译器可以。我使用的是VC++2008编译器,语言扩展关闭,级别4警告,它产生的唯一错误是我提到的。也不在G++下编译,但误差是不同的;它抱怨friend函数的模板参数会影响类的模板参数。它也不能隐式地将20转换为int。此外,值<0u始终为false!我会尝试用我的风格重写它,也许我能抓住潜在的错误。@Frigo:friend声明有点偏离参考。例如,但我认为Muhammad的编译器可以接受。我使用的是VC++2008编译器,语言扩展关闭,级别4警告,它产生的唯一错误是我提到的。虽然这是一个解决方案,这不是最好的解决方案,因为您盲目地与模板的所有实例化(包括潜在的专门化)交朋友。@大卫:当然,这是OP要做的设计决策。对我来说,我可能只会坚持一种类型的操作。如果你想变得有趣,你可以添加类型特征来检查两个组成类型是否都是可转换的。用下一个代码替换firend操作符,然后再试一次:friend int_t操作符+const int_t&lhs,const int_t&rhs{return int_tlhs+=rhs;}@Muhammad:如果你也删除一元操作符,那也可以。我更新了我的答案。虽然这是一个解决方案,但它不是最好的解决方案,因为您盲目地与模板的所有实例化(包括潜在的专门化)交朋友。@David:当然,这是OP的设计决策。对我来说,我可能只会坚持一种类型的操作。如果你想变得有趣,你可以添加类型特征来检查两个组成类型是否都是可转换的。用下一个代码替换firend操作符,然后再试一次:friend int_t操作符+const int_t&lhs,const int_t&rhs{return int_tlhs+=rhs;}@Muhammad:如果你也删除一元操作符,那也可以。我更新了我的答案。是的,正确的解释,它根本无法将int与无穷多的加法运算符匹配。他应该干脆放弃模板声明。朋友Itt操作符+ const int & x,const int & y {}.}:这个问题超出了演绎,考虑STD::min当int和long int通过或任何其他可转换但不同类型时,没有演绎问题,没有无限的可能性,但编译器无法使用该模板,因为类型在deduction@David:在int\u t中时,跳过模板参数列表可以使人更容易理解,就像friend int_t operator+..@phresnel:对,我没有考虑可读性:我已经编辑了答案并删除了本例中可选的模板参数。是的,正确的解释,它根本不会将int与无限多的加法运算符匹配。他应该干脆放弃模板声明。朋友Itt操作符+ const int & x,const int & y {}.}:这个问题超出了演绎,考虑STD::min当int和long int通过或任何其他可转换但不同类型时,没有演绎问题,没有无限的可能性,但编译器无法使用该模板,因为类型在deduction@David:在int\u t中时,跳过模板参数列表可以使人更容易理解,像friend int_t operator+..@phresnel一样:对,我没有考虑可读性:我编辑了答案并删除了本例中可选的模板参数。