问题描述
我一直试图为固定点类型实现一个复数类,其中乘法运算的结果类型将是输入类型的函数。我需要有一些函数,其中我可以通过复数乘复数,也可以通过实数乘复数。
这本质上是一个简化的代码版本。其中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;
}
名称查找:找到两个版本的 首先注意,返回类型永远不会被推导出来。您只需不能在返回类型上重载。正在推导 那么在调用 所以在生成候选函数集时,重载解析)模板被实例化,你会得到一个错误,因为 在您的原始代码中, 在您更新的代码中 使用更新后的代码,输出将是: 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 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 In your original code, the In your updated code With your updated code, output will be: 这篇关于当从封闭的模板类中导出返回类型时,函数解析失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! operator * : / code>
operator *
的模板参数,然后替换到返回类型模板中。
a * b;
会发生什么?首先, 版本的运算符*
已推导出其参数。对于第一过载, T2
被推导为 A
,并且对于第二过载 T2
解析为 double
。如果有多个重载,标准说: rt
没有嵌套的类型
。这就是为什么不选择更专门的第二个模板:不会发生重载分辨率。您可能希望此替换失败不会是错误。但是,标准说: 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