Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы.
Не гуглится и не кодится никак. Последнее где я застрял.
Убирая T3 полностью и заменяя его на явное B — помогает но это не то что нужно. Но и даже в этом случае приходится указывать все шаблонные параметры для вызова f() ручками, что нежелательно потому как весь смысл этой функции — это вывести все эти T1, .. T4 аргументы шаблона автоматически.
Цель работы — написать навороченный принтер типов, когда мы разваливаем входящий шаблон на запчасти, конвертируем в строку вложенные типы (через constexpr std::source_location::function_name()) и склеиваем всё это по какому-то шаблону, и всё в компайл-тайм.
Здравствуйте, johny5, Вы писали:
J>Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы. J>Не гуглится и не кодится никак. Последнее где я застрял. J>
J>Ошибки: J><source>:17:6: error: no matching function for call to 'f(A<int>::B<void>)' J> 17 | f( A<int>::B<void>() ); J> | ~^~~~~~~~~~~~~~~~~~~~~ J><source>:7:6: note: candidate: 'template<template<class> class T1, class T2, template<class> class T3, class T4> void f(typename T1<T2>::T3<T4>)' J> 7 | void f(typename T1<T2>::T3<T4> val) { } J> | ^ J><source>:7:6: note: template argument deduction/substitution failed: J><source>:17:6: note: couldn't deduce template parameter 'template<class> class T1' J> 17 | f( A<int>::B<void>() ); J> | ~^~~~~~~~~~~~~~~~~~~~~
J>Убирая T3 полностью и заменяя его на явное B — помогает но это не то что нужно. Но и даже в этом случае приходится указывать все шаблонные параметры для вызова f() ручками, что нежелательно потому как весь смысл этой функции — это вывести все эти T1, .. T4 аргументы шаблона автоматически. J>Цель работы — написать навороченный принтер типов, когда мы разваливаем входящий шаблон на запчасти, конвертируем в строку вложенные типы (через constexpr std::source_location::function_name()) и склеиваем всё это по какому-то шаблону, и всё в компайл-тайм. J>С++ 20++.
В сигнатуру структуры B не входит область ее определения, то есть, структура A. Убери T1 и T2, заработает
Здравствуйте, vopl, Вы писали:
V>Здравствуйте, johny5, Вы писали:
J>>Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы. J>>Не гуглится и не кодится никак. Последнее где я застрял.
J>>
J>>Ошибки:
J>><source>:17:6: error: no matching function for call to 'f(A<int>::B<void>)' J>> 17 | f( A<int>::B<void>() ); J>> | ~^~~~~~~~~~~~~~~~~~~~~
J>><source>:7:6: note: candidate: 'template<template<class> class T1, class T2, template<class> class T3, class T4> void f(typename T1<T2>::T3<T4>)' J>> 7 | void f(typename T1<T2>::T3<T4> val) { } J>> | ^
J>><source>:7:6: note: template argument deduction/substitution failed:
J>><source>:17:6: note: couldn't deduce template parameter 'template<class> class T1' J>> 17 | f( A<int>::B<void>() ); J>> | ~^~~~~~~~~~~~~~~~~~~~~
J>>Убирая T3 полностью и заменяя его на явное B — помогает но это не то что нужно. Но и даже в этом случае приходится указывать все шаблонные параметры для вызова f() ручками, что нежелательно потому как весь смысл этой функции — это вывести все эти T1, .. T4 аргументы шаблона автоматически.
J>>Цель работы — написать навороченный принтер типов, когда мы разваливаем входящий шаблон на запчасти, конвертируем в строку вложенные типы (через constexpr std::source_location::function_name()) и склеиваем всё это по какому-то шаблону, и всё в компайл-тайм.
J>>С++ 20++.
V>В сигнатуру структуры B не входит область ее определения, то есть, структура A.
Здравствуйте, johny5, Вы писали:
J>Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы.
Шаблонные параметры не могут быть выведены из такой конструкции, как ты описал. Полный список поддерживаемых конструкций здесь:
T
cv T
T*
T&
T&&
T[integer-constant]
template-name<T> (where template-name refers to a class template)
type(T)
T()
T(T)
T type::*
type T::*
T T::*
T (type::*)()
type (T::*)()
type (type::*)(T)
type (T::*)(T)
T (type::*)(T)
T (T::*)()
T (T::*)(T)
type[i]
template-name<i> (where template-name refers to a class template)
TT<T>
TT<i>
TT<>
--
Не можешь достичь желаемого — пожелай достигнутого.
R>T
R>cv T
R>T*
R>T&
R>T&&
R>T[integer-constant]
R>template-name<T> (where template-name refers to a class template)
R>type(T)
R>T()
R>T(T)
R>T type::*
R>type T::*
R>T T::*
R>T (type::*)()
R>type (T::*)()
R>type (type::*)(T)
R>type (T::*)(T)
R>T (type::*)(T)
R>T (T::*)()
R>T (T::*)(T)
R>type[i]
R>template-name<i> (where template-name refers to a class template)
R>TT<T>
R>TT<i>
R>TT<>
R>
Нужно только понимать, что это список элементарных форм, которые могут комбинироваться друг с другом, образуя более сложные формы. Например, T*& также является выводимой формой и является комбинацией форм T* и T&. Ну или, например, конструкция T[i], в которой выводятся и размер массива i, и тип элемента T, отсутствует в данном списке, поскольку эта форма может быть получена композицией двух простых форм: type[i] и T[integer-constant]. Ну и понятно, что сложность таких комбинаций ни чем не ограничивается — это могут быть всякие там const-volatile yказатели на функции, принимающие и возвращающие ссылки на многомерные массивы таких же сколь угодно сложных типов. А также подразумевается, что функции могут иметь какое угодно количество формальных параметров, описанных в т.ч. при помощи variadic packs. То же самое относится и к шаблонам (которые в данной нотации обозначаются как TT).
--
Не можешь достичь желаемого — пожелай достигнутого.
J>Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы.
Это невозможно, и вот почему
struct foo {
struct bar {};
};
struct boo {
using bar = foo::bar;
};
struct buz {};
struct xyz {
using bar = buz;
};
template<class T> struct ahaha {
struct bar {};
};
template<> struct ahaha<void> : foo {};
template<> struct ahaha<char> : boo {};
template<> struct ahaha<long> : xyz {};
template<class BAR> void g(BAR b) {
// ну и как вывести, какая структура / инстанс шаблона ahaha вложила в себя имя bar ?
}
int main() {
g(ahaha<int>::bar{});
g(ahaha<void>::bar{});
g(ahaha<char>::bar{});
g(ahaha<long>::bar{});
}
J>Цель работы — написать навороченный принтер типов, когда мы разваливаем входящий шаблон на запчасти, конвертируем в строку вложенные типы (через constexpr std::source_location::function_name()) и склеиваем всё это по какому-то шаблону, и всё в компайл-тайм.
Проще всего оснастить вложенные типы подсказками
template<class T> struct A {
template<class U> struct B {
using t_type = T;
using u_type = U;
.....
};
};
Перекуём баги на фичи!
Re[2]: Функция, принимающая вложенный класс шаблонного класс
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, johny5, Вы писали:
J>>Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы.
К>Это невозможно, и вот почему
Для моего варианта printer( A<int>::B<float> {} ); компилятор на самом деле выводит тип T1 (функции printer) как A<int>::B. Т.е. тип таки содержит объемлющую структуру.
Иначе если бы не так, какойнть printer( A<void>::B<float> {} ) создал бы ту же сигнатуру функции и всё это бы не слинковалось.
Осталось понять как этот составной тип T1 можно разложить дальше.
J>Немного магии: J>https://godbolt.org/z/ofhbhGGKc
J>Для моего варианта printer( A<int>::B<float> {} ); компилятор на самом деле выводит тип T1 (функции printer) как A<int>::B. Т.е. тип таки содержит объемлющую структуру.
Немного позандудствую: A<int>::B — это не тип, а шаблон типа (класса).
А теперь по существу. Я думаю, что ты совершенно напрасно использовал в своем примере шаблонный параметр шаблона. Пример стал сложнее, но это ни на шаг не приблизило тебя к решению. Ровно ту же самую проблему ты мог бы получить и на простом примере, с простым типом:
Получаешь все то же самое: копмилятор точно так же выводит тип T как A<int>::B<float> (только теперь уже это на самом деле тип, а не шаблон). И точно так же этот тип включает в себя объемлющий тип A<int>. Но только вот проблема в том, что ты не можешь написать такую функцию, котора позволила бы тебе этот тип (A<int>) вывести. Средства языка не позволяют это сделать.
--
Не можешь достичь желаемого — пожелай достигнутого.