Потому что так говорится в стандарте.
Стандарт гласит, что инвертирование произвольных карт времени компиляции эквивалентно Halt.
Это эквивалентно Остановке, потому что метапрограммирование шаблона завершено по Тьюрингу.
Он завершен по Тьюрингу, потому что на самом деле трудно создать полезный язык программирования, который не является полным по Тьюрингу; это происходит случайно, и избегание этого приводит к языку, который требует назойливого обходного пути для, казалось бы, простых вещей.
Таким образом, в целом проблема определения A
A<int, float>::B<0>
от этого преобразования и его реверсии является сложной, поэтому в стандарте C ++ говорится, что компилятор не пытается.
Если вы напишите свое собственное отображение, вы можете сделать это. Во-первых, вы должны понимать, что у типов B
нет "волос", поскольку в типе B
нет ничего такого, что присоединяет его к типу A
, который использовался для его создания. Мы можем добавить «волосы»:
template<class...Ts>
struct A {
template<unsigned i>
struct B {
using daddy = A;
int b;
};
};
теперь мы можем найти A
из типа B<?>
.
Далее давайте добавим несколько обратных карт:
template<class...Ts>
struct types_t {using type=types_t;};
template<class X>
struct get_types;
template<class X>
using get_types_t=typename get_types<X>::type;
template<template<class...>class Z, class...Ts>
struct get_types<Z<Ts...>>:types_t<Ts...>{};
template<class B>
struct get_B_index;
template<unsigned i, template<unsigned>class B>
struct get_B_index<B<i>>:std::integral_constant<unsigned, i>{};
и из этого мы можем получить A
аргументы шаблона из B
:
template<class...Ts, unsigned i>
void foo( types_t<Ts...>, std::integral_constant<unsigned, i>, typename A<Ts...>::template B<i> var ) {
}
template<class B>
void foo( B b ) {
using types = get_types_t< typename B::daddy >;
using index = get_B_index< B >;
return foo( types{}, index{}, b );
}
Живой пример