Reputation: 177
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.
Upvotes: 0
Views: 385
Reputation: 320481
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, i.e. 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)
{
...
}
};
Upvotes: 4