Вы можете просто использовать параметр шаблона шаблона:
template<typename T>
struct data1;
template<typename T>
struct fun1 {
using type = data1<T>;
};
template<typename T>
struct fun2;
template<class T>
struct fun2<data1<T>>{
using type = data1<T>;
};
template<template<class> class X, class T>
struct fun2<X<T>>
: fun2<typename X<T>::type>{};
Тесты:
#include <type_traits>
static_assert(std::is_same<fun2<data1<int>>::type, data1<int>>::value, "fun2<data1<int>>");
static_assert(std::is_same<fun2<data1<fun1<int>>>::type, data1<fun1<int>>>::value, "fun2<data1<fun1<int>>>");
static_assert(std::is_same<fun2<fun1<int>>::type, data1<int>>::value, "fun2<fun1<int>>");
static_assert(std::is_same<fun2<fun2<fun1<int>>>::type, data1<int>>::value, "fun2<fun2<fun1<int>>>");
int main(){
}
Живой пример на Ideone (с использованием псевдонимов, измененных на typedefs) .