我遇到“无法推断T模板参数”错误的问题。
这是我的班级:
class PropertyAccess
{
public:
template <typename TClass, typename TType>
struct SetterPointer { typedef void (TClass::*Type)(const TType&); };
template <typename TClass, typename TType>
struct GetterPointer { typedef TType(TClass::*Type)(); };
template <typename TClass, typename TType>
void Assign(
TClass* object,
typename SetterPointer<TClass, TType>::Type setter,
typename GetterPointer<TClass, TType>::Type getter)
{
...
}
}
以下是我如何使用它:
class Test
{
public:
int a;
void Set(const int& v) { a = v; }
int Get() { return a; }
};
void main
{
Test test;
PropertyAccess property;
property.Assign(&test, &Test::Set, &Test::Get); <---here is compile error
}
如果我尝试编译该代码,我有错误:
'void PropertyAccess::Assign(TClass *,PropertyAccess::SetterPointer<TClass,TType>::Type,PropertyAccess::GetterPointer<TClass,TType>::Type)' : could not deduce template argument for 'TType'
但如果我将Assign方法更改为:
void Assign(
TClass* object,
typename SetterPointer<TClass, TType>::Type setter,
TType(TClass::*getter)())
{
...
}
然后一切都好。为什么?我知道如果它没有args,那么函数类型是无法推导出来的,但是为什么它在第二种情况下有效呢?
我使用Visual Studio 2013 C ++ compiller。
答案 0 :(得分:4)
C ++无法从其嵌套类型中推断出封闭类型。这是非推断上下文的一个示例。
最简单的例子就是
struct S { typedef int T; };
template <typename C> void foo(typename C::T i) {}
int main() {
int x = 0;
foo(x); // ERROR: non-deduced context
}
或者,更接近代码中的内容
template <typename X> struct S { typedef X T; };
template <typename X> void foo(typename S<X>::T i) {}
int main() {
int x = 0;
foo(x); // ERROR: non-deduced context
}
同样的事情也发生在你的情况下,以一种稍微复杂的形式出现。对于模板方法Assign
,无法通过TClass
等函数参数推导出模板参数TType
和typename SetterPointer<TClass, TType>::Type setter
。在您的案例中,模板参数TClass
可以从Assign
的第一个参数中推导出来,但TType
不能从任何参数中推断出来。因此错误。
当您将Assign
的最后一个参数的声明更改为TType(TClass::*getter)()
时,您立即使上下文可以推断,即编译器使用getter参数作为推断TType
的机会。
在C ++ 11中,您可以使用别名模板来实现相同的typedef
效果,并且仍然可以保持上下文可推导
class PropertyAccess
{
public:
template <typename TClass, typename TType>
using SetterPointer = void (TClass::*)(const TType&);
template <typename TClass, typename TType>
using GetterPointer = TType(TClass::*)();
template <typename TClass, typename TType>
void Assign(
TClass* object,
SetterPointer<TClass, TType> setter,
GetterPointer<TClass, TType> getter)
{
...
}
};