using задаёт alias, и вроде когда передаёшь инстанс такого алиаса (using_fun) функции, шаблонные аргументы выводятся как будто я передал оригинальный класс (std::variant<int, long>). И я могу задетектировать сам std::variant, но не могу передавая тип оригинального using-а как template template аргумент, задетектировать что он был использован. Не понимаю почему.
В общем застрял, есть какие то может готовые решения?
Здравствуйте, johny5, Вы писали:
J>using задаёт alias, и вроде когда передаёшь инстанс такого алиаса (using_fun) функции, шаблонные аргументы выводятся как будто я передал оригинальный класс (std::variant<int, long>). И я могу задетектировать сам std::variant, но не могу передавая тип оригинального using-а как template template аргумент, задетектировать что он был использован.
J>Не понимаю почему.
Сам же выше и ответил. Потому что не вводится новый тип.
J>В общем застрял, есть какие то может готовые решения?
Здравствуйте, andrey.desman, Вы писали:
AD>Здравствуйте, johny5, Вы писали:
J>>using задаёт alias, и вроде когда передаёшь инстанс такого алиаса (using_fun) функции, шаблонные аргументы выводятся как будто я передал оригинальный класс (std::variant<int, long>). И я могу задетектировать сам std::variant, но не могу передавая тип оригинального using-а как template template аргумент, задетектировать что он был использован.
J>>Не понимаю почему.
AD>Сам же выше и ответил. Потому что не вводится новый тип.
Ну хорошо, не вводится новый тип. Тогда почему когда я передаю using_fun как template template параметр, он не превращается магически в std::variant? С чем конкретно тогда оперирует мой шаблон? Т.е. 46я и 47я строчки должны бы давать одинаковый результат?
Здравствуйте, johny5, Вы писали:
J>Ну хорошо, не вводится новый тип. Тогда почему когда я передаю using_fun как template template параметр, он не превращается магически в std::variant? С чем конкретно тогда оперирует мой шаблон? Т.е. 46я и 47я строчки должны бы давать одинаковый результат?
Невнимательно прочитал вопрос.
An alias template name is never deduced.
То есть, использовать имя шаблонного алиаса таким образом не получится, оно не выведется из аргумента. Надо либо указывать базовый шаблон или сравнивать уже полный тип is_same_v<using_fun<long>, decltype(d)>.
J>using задаёт alias, и вроде когда передаёшь инстанс такого алиаса (using_fun) функции, шаблонные аргументы выводятся как будто я передал оригинальный класс (std::variant<int, long>). И я могу задетектировать сам std::variant, но не могу передавая тип оригинального using-а как template template аргумент, задетектировать что он был использован. Не понимаю почему.
Можно упростить пример — чтобы он не ложно-отрицательный ответ давал на SFINAE, а тупо не компилировался
К>int main() {
К> std::variant<int, long> a;
К> check(a);
К> check<std::variant>(a);
К> nocheck<std::variant, int, long>(a);
К> check<std::variant, int>(a); // long довывелся
К> check<std::variant, int, long>(a);
К> //check<using_fun>(a); // как вывести T для using_fun<T> из variant<int,long> ?
К> //check1(a); // ну, тут понятно: ждём шаблон с 1 параметром, а подсунули с двумя
К> check1<using_fun>(a);
К> check1<using_fun, long>(a);
К>}
К>
Если ещё добавить с вектором
int main() {
using_fun<long> a;
check<std::variant>(a);
check<using_fun>(a); // как вывести T для using_fun<T> из variant<int,long> ?
check<std::vector>(a); // тоже ломается :()
}
И в целом различить вектор от using_fun получается невозможным.
Если компайлер заставить распечатать тип:
template<template<typename...> class TEMPLATE>
void print() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
int main() {
print<using_fun>();
}
void print() [with TEMPLATE = using_fun]
Т.е. using_fun магически превращается в тип, который, при этом, никак нельзя decay-ить в std::variant. Это что то ad-hoc, не думаю что это оговорено в стандарте.
J>int main() {
J> using_fun<long> a;
J> check<using_fun>(a); // как вывести T для using_fun<T> из variant<int,long> ?
J>}
J>
Из ошибкок компилятора можно понять что он спотыкается при попытке сведЕния пака и штучного параметра. Вероятно, это какая то тонкая недоработка языка, потому что в других ситуациях такое сведение делается замечательно. Ближе к практике. Если обеспечить наличие перегрузки check, в которой не надо будет сводить пак со штучным параметром, то все получается нормально. А именно:
#include <variant>
#include <iostream>
template<template<typename...> class TEMPLATE, class... PARAMS>
void check(TEMPLATE<PARAMS...>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<template<typename...> class TEMPLATE, class PARAM1> // <---- в этой перегрузке именно параметр, а не пакvoid check(TEMPLATE<PARAM1>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template<typename T>
using using_fun = std::variant<int, T>;
int main() {
using_fun<long> a;
check<using_fun>(a); // как вывести T для using_fun<T> из variant<int,long> ?
}
ААааа.. просто прорыв! Даже в сорцах STL я этого не увидел, у них там моя оригинальная блеклая версия.
Никогда бы не подумал, что вариадики окажутся слабее ручной раскрутки шаблона на разное количество аргументов.