Функция, принимающая вложенный класс шаблонного класса.
От: johny5 Новая Зеландия
Дата: 04.04.24 03:08
Оценка:
Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы.
Не гуглится и не кодится никак. Последнее где я застрял.

template<template<typename> typename T1, typename T2,
  template<typename> typename T3, typename T4>
void f(typename T1<T2>::T3<T4> val) {  }

template<typename T>
struct A
{
    template<typename S>
    struct B{};
};

int main() {
    f( A<int>::B<void>() );
}



Ошибки:

<source>:17:6: error: no matching function for call to 'f(A<int>::B<void>)'
17 | f( A<int>::B<void>() );
| ~^~~~~~~~~~~~~~~~~~~~~

<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>)'
7 | void f(typename T1<T2>::T3<T4> val) { }
| ^

<source>:7:6: note: template argument deduction/substitution failed:

<source>:17:6: note: couldn't deduce template parameter 'template<class> class T1'
17 | f( A<int>::B<void>() );
| ~^~~~~~~~~~~~~~~~~~~~~


Убирая T3 полностью и заменяя его на явное B — помогает но это не то что нужно. Но и даже в этом случае приходится указывать все шаблонные параметры для вызова f() ручками, что нежелательно потому как весь смысл этой функции — это вывести все эти T1, .. T4 аргументы шаблона автоматически.

Цель работы — написать навороченный принтер типов, когда мы разваливаем входящий шаблон на запчасти, конвертируем в строку вложенные типы (через constexpr std::source_location::function_name()) и склеиваем всё это по какому-то шаблону, и всё в компайл-тайм.

С++ 20++.
Отредактировано 04.04.2024 3:10 johny5 . Предыдущая версия .
Re: Функция, принимающая вложенный класс шаблонного класса.
От: vopl Россия  
Дата: 04.04.24 08:22
Оценка: 4 (1)
Здравствуйте, johny5, Вы писали:


J>Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы.

J>Не гуглится и не кодится никак. Последнее где я застрял.

J>
J>template<template<typename> typename T1, typename T2,
J>  template<typename> typename T3, typename T4>
J>void f(typename T1<T2>::T3<T4> val) {  }

J>template<typename T>
J>struct A
J>{
J>    template<typename S>
J>    struct B{};
J>};

J>int main() {
J>    f( A<int>::B<void>() );
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, заработает
  Скрытый текст
template<
    template<typename> typename T3, typename T4>
void f( T3<T4> val) {  }

template<typename T>
struct A
{
    template<typename S>
    struct B{};
};

int main() {
    f( A<int>::B<void>() );
}
Re[2]: Функция, принимающая вложенный класс шаблонного класса.
От: vopl Россия  
Дата: 04.04.24 08:27
Оценка:
Здравствуйте, vopl, Вы писали:

V>Здравствуйте, johny5, Вы писали:



J>>Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы.

J>>Не гуглится и не кодится никак. Последнее где я застрял.

J>>
J>>template<template<typename> typename T1, typename T2,
J>>  template<typename> typename T3, typename T4>
J>>void f(typename T1<T2>::T3<T4> val) {  }

J>>template<typename T>
J>>struct A
J>>{
J>>    template<typename S>
J>>    struct B{};
J>>};

J>>int main() {
J>>    f( A<int>::B<void>() );
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.


Упс.. Входит https://eel.is/c++draft/intro.defs#defns.signature.member.templ
Re: Функция, принимающая вложенный класс шаблонного класса.
От: rg45 СССР  
Дата: 04.04.24 09:59
Оценка: 4 (1)
Здравствуйте, johny5, Вы писали:

J>Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы.


Шаблонные параметры не могут быть выведены из такой конструкции, как ты описал. Полный список поддерживаемых конструкций здесь:

https://timsong-cpp.github.io/cppwp/n4861/temp.deduct.type#8

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<>
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 04.04.2024 11:55 rg45 . Предыдущая версия .
Re[2]: Функция, принимающая вложенный класс шаблонного класс
От: rg45 СССР  
Дата: 04.04.24 18:13
Оценка:
R>https://timsong-cpp.github.io/cppwp/n4861/temp.deduct.type#8

R>
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).
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 04.04.2024 20:08 rg45 . Предыдущая версия . Еще …
Отредактировано 04.04.2024 20:05 rg45 . Предыдущая версия .
Отредактировано 04.04.2024 20:04 rg45 . Предыдущая версия .
Отредактировано 04.04.2024 18:17 rg45 . Предыдущая версия .
Отредактировано 04.04.2024 18:16 rg45 . Предыдущая версия .
Отредактировано 04.04.2024 18:14 rg45 . Предыдущая версия .
Re: Функция, принимающая вложенный класс шаблонного класса.
От: Кодт Россия  
Дата: 05.04.24 10:38
Оценка: 4 (1)
Здравствуйте, johny5, Вы писали:


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 Новая Зеландия
Дата: 10.04.24 19:16
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, johny5, Вы писали:



J>>Нужно написать шаблонную функцию, которая принимала бы аргументом вложенный шаблонный класс шаблонного класса и сама вывела бы все шаблонные аргументы.


К>Это невозможно, и вот почему


Немного магии:
https://godbolt.org/z/ofhbhGGKc

Для моего варианта printer( A<int>::B<float> {} ); компилятор на самом деле выводит тип T1 (функции printer) как A<int>::B. Т.е. тип таки содержит объемлющую структуру.
Иначе если бы не так, какойнть printer( A<void>::B<float> {} ) создал бы ту же сигнатуру функции и всё это бы не слинковалось.

Осталось понять как этот составной тип T1 можно разложить дальше.
Отредактировано 10.04.2024 19:18 johny5 . Предыдущая версия .
Re[3]: Функция, принимающая вложенный класс шаблонного класс
От: rg45 СССР  
Дата: 12.04.24 12:45
Оценка:
Здравствуйте, johny5, Вы писали:


J>Немного магии:

J>https://godbolt.org/z/ofhbhGGKc

J>Для моего варианта printer( A<int>::B<float> {} ); компилятор на самом деле выводит тип T1 (функции printer) как A<int>::B. Т.е. тип таки содержит объемлющую структуру.


Немного позандудствую: A<int>::B — это не тип, а шаблон типа (класса).

А теперь по существу. Я думаю, что ты совершенно напрасно использовал в своем примере шаблонный параметр шаблона. Пример стал сложнее, но это ни на шаг не приблизило тебя к решению. Ровно ту же самую проблему ты мог бы получить и на простом примере, с простым типом:

template<typename T>
void printer(T val)
{
    std::cout << "magic: ";
    print_type<T>();

}


Получаешь все то же самое: копмилятор точно так же выводит тип T как A<int>::B<float> (только теперь уже это на самом деле тип, а не шаблон). И точно так же этот тип включает в себя объемлющий тип A<int>. Но только вот проблема в том, что ты не можешь написать такую функцию, котора позволила бы тебе этот тип (A<int>) вывести. Средства языка не позволяют это сделать.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 12.04.2024 13:38 rg45 . Предыдущая версия . Еще …
Отредактировано 12.04.2024 12:48 rg45 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.