当从封闭的模板类中导出返回类型时,函数解析失败 [英] function resolution failed when return type is deduced from enclosed template class
问题描述
我一直试图为固定点类型实现一个复数类,其中乘法运算的结果类型将是输入类型的函数。我需要有一些函数,其中我可以通过复数乘复数,也可以通过实数乘复数。
这本质上是一个简化的代码版本。其中A是我的复杂类型。
模板< typename T1,typename T2> struct rt {};
模板<> struct rt< double,double> {
typedef double type;
};
// forward declaration
template< typename T> struct A;
template< typename T1,typename T2>
struct a_rt {
typedef A< typename rt< T1,T2> :: type>类型;
};
template< typename T>
struct A {
template< typename T2>
typename a_rt< T,T2> :: type operator *(const T2& val)const {
typename a_rt< T,T2&
cout<< T2& called<< endl
return ret;
}
template< typename T2>
typename a_rt< T,T2> :: type operator *(const A< T2& val)const {
typename a_rt< T,T2&
cout<< A< T2&被称为 endl
return ret;
}
};
TEST(TmplClassFnOverload,Test){
A< double>一个;
A< double> b;
double c;
a * b;
a * c;
}
代码无法编译,因为编译器试图实例化 $
和 A< double>
的$ c> a_rt 我不知道发生了什么,因为我想象编译器应该选择更专业的运算符*(A< double>&)
所以 a_rt
将仅以< double,double>
作为参数进行实例化。
您能向我解释为什么这不行吗?
如果这是一个限制,我该如何解决这个问题。
感谢一吨!
unittest.cpp:在实例化'a_rt< double,A< >':
unittest.cpp:198:从这里实例化
unittest.cpp:174:错误:没有类型命名为'type'in'struct rt< double,A& >'
更新:
编译器似乎对以下更改感到满意。有一些细微我在这里失踪。感谢一个能够让我了解编译器在这两种情况下做什么的人。
template< typename T2>
A< typename rt< T,T2> :: type>运算符*(const T2& val)const {
A< typename rt< T,T2> :: type& ret;
cout<< T2& called<< endl
return ret;
}
template< typename T2>
A< typename rt< T,T2> :: type>运算符*(const A< T2& val)const {
A< typename rt< T,T2> :: type& ret;
cout<< A< T2&被称为 endl
return ret;
}
名称查找:找到两个版本的 首先注意,返回类型永远不会被推导出来。您只需不能在返回类型上重载。正在推导 那么在调用 14.7.1隐式实例化[temp.inst]子句9 如果函数模板或成员函数模板专用化是以涉及重载解析的方式使用 所以在生成候选函数集时,重载解析)模板被实例化,你会得到一个错误,因为 14.8.2模板参数扣除[temp.deduct]子句8 p> 如果替换导致无效的类型或表达式,请键入 在您的原始代码中, 在您更新的代码中 使用更新后的代码,输出将是: I have been trying to implement a complex number class for fixed point types where the result type of the multiply operation will be a function of the input types. I need to have functions where I can do multiply complex by complex and also complex by real number. This essentially is a simplified version of the code. Where A is my complex type. The code fails to compile because the compiler is trying to instantiate the Would you please explain to me why this would not work?
And if this is a limitation, how should I work around this. Thanks a tonne! Update The compiler appears to be happy with the following change. There is some subtlety I'm missing here. Appreciate someone who can walk me through what the compiler is doing in both cases.
Resolving function calls in C++ proceeds in five phases: First note that the return type is never ever being deduced. You simply cannot overload on return type. The template arguments to So what happens at the call 14.7.1 Implicit instantiation [temp.inst] clause 9 If a function template or a member function template specialization is
used in a way that involves overload resolution, a declaration of the
specialization is implicitly instantiated (14.8.3). So at the end of argument deduction when the set of candidate functions are being generated, (so before overload resolution) the template gets instantiated and you get an error because 14.8.2 Template argument deduction [temp.deduct] clause 8 If a substitution results in an invalid type or expression, type
deduction fails. An invalid type or expression is one that would be
ill-formed if written using the substituted arguments.
Only invalid types and expressions in the immediate context of the
function type and its template parameter types can result in a
deduction failure. [ Note: The evaluation of the substituted types and
expressions can result in side effects such as the instantiation of
class template specializations and/or function template
specializations, the generation of implicitly-defined functions, etc.
Such side effects are not in the "immediate context" and can result in
the program being ill-formed. — end note ] In your original code, the In your updated code With your updated code, output will be:
这篇关于当从封闭的模板类中导出返回类型时,函数解析失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! operator * : / code>
operator *
的模板参数,然后替换到返回类型模板中。
a * b;
会发生什么?首先, 版本的运算符*
已推导出其参数。对于第一过载, T2
被推导为 A
,并且对于第二过载 T2
解析为 double
。如果有多个重载,标准说:
,则会隐式地声明
专用化实例化(14.8.3)。
rt
没有嵌套的类型
。这就是为什么不选择更专门的第二个模板:不会发生重载分辨率。您可能希望此替换失败不会是错误。但是,标准说:
扣除失败。无效的类型或表达式是如果使用替换参数写入将
不成形。
在
函数类型及其模板参数类型的直接上下文中,只有无效的类型和表达式可能导致
推导失败。 [注意:对替换类型和
表达式的求值可能导致副效应,例如
类模板专用化和/或函数模板
专用化的实例化,隐式定义函数的生成等等。
这样的边效应不在直接上下文,并且可能导致
程序不合格。 - end note]
typename a_rt< T,T2> / code>返回类型不是直接上下文。只有在模板实例化期间,它被评估,然后缺少在
rt
中的嵌套类型
是一个错误。
A< typename rt< T,T2> :: type>
上下文,并且替换失败不是错误(SFINAE)适用:未推导的函数模板被简单地从重载分辨率集中移除,并且剩下的一个被调用。
A< T2&称为
> T2&称为
template<typename T1, typename T2> struct rt {};
template<> struct rt<double, double> {
typedef double type;
};
//forward declaration
template<typename T> struct A;
template<typename T1, typename T2>
struct a_rt {
typedef A<typename rt<T1,T2>::type> type;
};
template <typename T>
struct A {
template<typename T2>
typename a_rt<T,T2>::type operator*(const T2& val) const {
typename a_rt<T,T2>::type ret;
cout << "T2& called" << endl;
return ret;
}
template<typename T2>
typename a_rt<T,T2>::type operator*(const A<T2>& val) const {
typename a_rt<T,T2>::type ret;
cout << "A<T2>& called" << endl;
return ret;
}
};
TEST(TmplClassFnOverload, Test) {
A<double> a;
A<double> b;
double c;
a * b;
a * c;
}
a_rt
template with double
and A<double>
. I don't know what is going on under the hood since I imagine the compiler should pick the more specialized operator*(A<double>&)
so a_rt
will only be instantiated with <double, double>
as arguments. unittest.cpp: In instantiation of 'a_rt<double, A<double> >':
unittest.cpp:198: instantiated from here
unittest.cpp:174: error: no type named 'type' in 'struct rt<double, A<double> >'
template<typename T2>
A<typename rt<T,T2>::type> operator*(const T2& val) const {
A<typename rt<T,T2>::type> ret;
cout << "T2& called" << endl;
return ret;
}
template<typename T2>
A<typename rt<T,T2>::type> operator*(const A<T2>& val) const {
A<typename rt<T,T2>::type> ret;
cout << "A<T2>& called" << endl;
return ret;
}
operator*
operator*
are being deduced and then substituted into the return type template. a * b;
? First, both versions of operator*
have their arguments deduced. For the first overload, T2
is deduced to being A<double>
, and for the second overload T2
resolves to double
. If there multiple overloads, the Standard says:
rt
does not have a nested type
. This is why the more specialized second template will not be selected: overload resolution does not take place. You might have expected that this substitution failure would not be an error. HOwever, the Standard says:
typename a_rt<T,T2>::type
return type is not an immediate context. Only during template instantiation does it get evaluated, and then the lack of the nested type
in rt
is an erorr. A<typename rt<T,T2>::type>
return type is an immediate context and the Substitution Failure is Not An Erorr (SFINAE) applies: the non-deduced function template is simply removed from the overload resolution set and the remaining one is being called. > A<T2>& called
> T2& called