如果使用typedef,则无法推断模板参数

时间:2015-07-01 21:02:27

标签: c++

我遇到“无法推断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。

1 个答案:

答案 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等函数参数推导出模板参数TTypetypename 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)
    {
       ... 
    }
};