Assume we have a given class ABC
that is templated with K
and V
:
template <typename K, typename V>
using ABC = AnotherClass<K, V>
I know that it is possible to implement type traits that check if a template T
is of the given class ABC
, eg:
template <typename T>
struct is_class_abc : std::false_type {};
template <typename K, typename V>
struct is_class_abc<ABC<K, V>> : std::true_type {};
Assume we change the ABC
definition to be AnotherClass
with types that change depending on K
and V
:
template <typename K, typename V>
using ABC = AnotherClass<typename std::conditional<
CONDITION, SOMETHING, SOMETHIN_ELSE>::type, ... >
The condition, something and something_else all depend and rely on K-V.
I get this compile error:
Class template partial specialization contains template parameters that cannot be deduced; this partial specialization will never be used
Non-deducible template parameter 'K'
Same for V
.
Any idea if it is possible to do this? If so, how do I make it work?
The partial specialization will not only check if the passed type is of the form ABC<K,V>
but it also will try/need to deduce K
and V
. Now let's look at how this would work. Assume we pass the type trait should check ABC<K, V>
. Since ABC
is only a type alias, the actual type passed to this type trait will actually be of the form AnotherClass<K',V'>
where K'
and V'
are some modification of K
and V
.
Now the type trait would need to deduce K
and V
back from K'
and V'
, this is really necessary since it is possible that there are no such K
and V
. But since you use the std::conditional<...>::type
, it is not transparent to the compiler what is going on there. This is called a non-deduced context. Basically, there some easy cases where we can deduce in the backwards direction (e.g. if you habe ABC = AnotherClass<const K, V>
). In many cases (such as when you use a typedef inside another type, like here) that is to complicated/not possible.
This is not always intuitive and sometimes baffling, such as here:
template<class>
struct is_const : std::false_type {};
template<class T>
struct is_const<const T> : std::true_type {}; // This works
template<class T>
struct is_const<typename add_const<T>::type> : std::true_type {}; // This does NOT work
The second specialization also only adds a const such as const T
does, but this is hidden (aka in a non-deduced context) and hence we cannot deduce T
.