简体   繁体   中英

could not deduce template argument if using typedef

I have a problem with "Could not deduce template argument for T" error.

here is my class:

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)
    {
        ...
    }
}

and here is how I use it:

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
}

If i try to compile that code, I have error:

'void PropertyAccess::Assign(TClass *,PropertyAccess::SetterPointer<TClass,TType>::Type,PropertyAccess::GetterPointer<TClass,TType>::Type)' : could not deduce template argument for 'TType'

but if I change Assign method to:

void Assign(
        TClass* object,
        typename SetterPointer<TClass, TType>::Type setter,
        TType(TClass::*getter)())
    {
        ...
    }

then everything is alright. Why? I know that function type cannot be deduced if it has no args, but why it works in second case?

I use Visual Studio 2013 C++ compiller.

C++ cannot deduce the enclosing type from its nested type. It is an example of non-deduced context .

A simplest example would be something like

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
}

or, closer to what you have in your code

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
}

The same thing happens in your case as well, in a slightly more convoluted form. For template method Assign it is not possible to deduce template parameters TClass and TType through a function parameter like typename SetterPointer<TClass, TType>::Type setter . In your case template parameter TClass is deducible from the first argument of Assign , but TType is not deducible from any argument. Hence the error.

When you change declaration of the last parametr of Assign to TType(TClass::*getter)() you immediately make the context deducible, ie the compiler uses the getter argument as an opportunity to deduce TType .

In C++11 you can use alias templates to achieve the same typedef effect and still keep the context deducible

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)
    {
       ... 
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM