I stumbled over some behaviour regarding template argument deduction in context with alias templates, I am not understanding.
The basic setup is as follows:
#include <type_traits>
#include <iostream>
// class-template:
template<typename tpProxy, typename ...tpElements>
struct basic_id {};
// alias template for the above defined class-template:
template<typename tpTypeValue, tpTypeValue ...tpValues>
using value_id = basic_id<std::integral_constant<tpTypeValue, 0>,
std::integral_constant<tpTypeValue, tpValues>...>;
I then tried to deduce the template arguments of a value_id instantiation (as for example in the below shown trait class template). My first approach was to use the value_id alias template directly in the argument list of the partial template specialization:
// 1st approach of a traits class for value_id:
template<typename tpValueID>
struct is_value_id_1st_approach : std::false_type {};
template<typename tpTypeValue, tpTypeValue ...tpValues>
struct is_value_id_1st_approach<value_id<tpTypeValue, tpValues...>> : std::true_type {};
My second approach, after realizing that the first one wasn't working, was to directly write the value_id definition into the argument list, which then worked for MSVC as well as GCC:
// 2nd approach; this time with directly given template-instantiation:
template<typename tpValueID>
struct is_value_id_2nd_approach : std::false_type {};
template<typename tpTypeValue, tpTypeValue ...tpValues>
struct is_value_id_2nd_approach<basic_id<std::integral_constant<tpTypeValue, 0>,
std::integral_constant<tpTypeValue, tpValues>...>> : std::true_type {};
int main() {
using my_value_id = value_id<int, 1, 2, 3>;
std::cout << "is_value_id_1st_approach = " << std::boolalpha <<
is_value_id_1st_approach<my_value_id>::value << std::endl; // false
std::cout << "is_value_id_2nd_approach = " << std::boolalpha <<
is_value_id_2nd_approach<my_value_id>::value << std::endl; // true
}
But why is the first approach not working, when the second one is?
As Johannes Schaub wrote in a related post:
"They [alias templates] are as deducible as the equivalent code without using template aliases."
I also defined a further alias template for which both approaches are functional:
template<typename ...tpTypes>
using id = basic_id<void, tpTypes...>;
So the below trait class template is able to deduce the template arguments of an id instantiation:
template<typename tpID>
struct is_id : std::false_type {};
template<typename ...tpTypes>
struct is_id<id<tpTypes...>> : std::true_type {};