Нашли или выдавили из себя код, который нельзя назвать нормальным,
на который без улыбки не взглянешь?
Не торопитесь его удалять или рефакторить, — запостите его на
говнокод.ру, посмеёмся вместе!
using System;
public interface IFoo
{
void WhoAmI<T>(T t);
}
public class Foo : IFoo
{
public void WhoAmI<T>(T t)
{
Console.WriteLine(t.GetType().FullName);
}
}
class pituh
{
public static int Main(string[] args)
{
var f = new Foo() as IFoo;
f.WhoAmI("asd");
f.WhoAmI(10);
return 0;
}
}
Решите задачку.
есть некий код на C#
using System;
public interface IFoo
{
void WhoAmI<T>(T t);
}
public class Foo : IFoo
{
public void WhoAmI<T>(T t)
{
Console.WriteLine(t.GetType().FullName);
}
}
class pituh
{
public static int Main(string[] args)
{
var f = new Foo() as IFoo;
f.WhoAmI("asd");
f.WhoAmI(10);
return 0;
}
}
Для gcc/clang есть abi::__cxa_demangle. Думаю, что мелкомягкие тоже что-то выдумали (явно не как у людей).
Иными словами, парочка #if с проверкой на компилятор/окружение должны решить вопрос c кросс-компиляторным demangle. Я почти уверен, что на GitHub (or whatever) уже можно найти рабочий код.
P.S. abi::__cxa_demangle дико бесит, что не constexpr. А ведь тип вполне себе известен на этапе компиляции. Такое ограничение не дает делать constexpr там, где надо получить имя типа...
Это шуточка была. А если серьезно, то в плюсах аналогичное реализуемо с помощью boost::any и boost::demangle. И на сколько я понимаю, в сисярпе под копотом оно работает как раз примерно так.
в сисяпре оно работает как есть. т.к. виртуальная таблица хранит указатель на дженерик метод который переводиться в специализацию во время выполнения кода. а значит никакого кастинга делать не приходиться из-за того что используется тип генерика
А в C++ вообще на этапе компиляции известно, какая конкретная реализация шаблона выполняется, и поэтому тем более не приходится ничего ни к чему кастовать.
ну в принципе да. но если прогнать через функцию тогда у компилятора облом будет, но он изначально скажет что виртуальные теплейтные функции идут в лес 🙂
не важно сколько оно проведет время ее результат определить не возможно т.к. у компилятора нет метода определить какой класс является владельцем интерфейса(ака абстрактного класа) а значит "задача оптимизации" результата не имеет и оптимизация прозведенна не может быть. кроме одного случая о котором написал bormand
Указанный код работает за небольшой промежуток времени, результат его выполнения не изменяется от запуска к запуску и может быть легко вычислен ещё на стадии написания программы. Нельзя доказать отсутствие компилятора, который проведёт эту оптимизацию.
class main
{
public static int Main(string[] args)
{
System.Console.WriteLine("System.String");
System.Console.WriteLine("System.Int32");
return 0;
}
}
Лучше вставить выбор дочернего класса в зависимости от пользовательского ввода.
Да, общий случай никто не предскажет и не запилит пацанский пирфоманс. Печально.
Собсно в этом и разница шаблона и генерика.
Ибо генерик вообще не шаблон, это сахарок над Foo<Object>.
В крестах же напротив, шаблонный метод виртуальным не сделать.
Асд77 выше утверждает, что там не касты в рантайме, а инстанцирование шаблонного метода в рантайме (типа сисярп в рантайме конпелирует конкретную реализацию, как jit). Это если я правильно его понял. Сам-то я не знаю и гуглить не хочу.
using System;
namespace Rextester
{
public class Collection<T> {};
public class Program
{
static int f(Collection<int> c) { return 1; }
static int f(Collection<string> c) { return 2; }
public static void Main(string[] args)
{
//Your code goes here
Console.WriteLine(f((Collection<int>)null));
Console.WriteLine(f((Collection<string>)null));
}
}
}
ок, спасибо, почитал про разницу в генериках java vs c#
ну тогда другой пример - template specialization:
int f<T>(T c) { return 1; }
int f<>(string c) { return 2; } // c# не может в <>, на стековерфлоу советуют их убрать и получить просто перегрузку
int g<T>(T c) { return f(c); }
call g((string)null);
если кококомпилятор c# сохраняет информацию о типах, и сам по себе язык обмазан сахаром в 10 слоев, что им помешало реализовать такую несложную вещь, как частичная/полная специализация?
ну или аналог крестушкового template <int N, int M> class Matrix()
раз уж так хочется сравнить несравнимое
интересно послушать
ну совсем одно и то же, ага!
такой dynamic cast даже в pl/sql есть, прости господи
а можно за O(0) всё таки - компилятор же знает о типе объекта, почему он не выбирает сразу правильную "перегрузку" из набора функций?
или про отсутствие type erasure маркетинговые презентации всё же немного подпёздывают?
> метод который переводиться
> делать не приходиться
> это бред - не говорят не люди не коты.
> что бы компелятор
> там виртуальная функция для особо одаренных стоит что бы компелятор от с++ жидко обгадился когда начнет применять темплейты к фиртуальной функции
Да это же вореционный бот, который своим кобенаторным алгоритмом осознал C++ до возможности написания своего буста, но русский язык учил по комментариям на Ютубе.
А если WhoAmI(const std::type_info&) захочет распечатать само значение, дать ему ссылку на IPrinter, которую создавать в WhoAmI(const T &t), пока тип и значение известны.
Вынос базового приватного (да, они нормально работают и в "private") виртуального метода в public -- личная психологическая проблема автора дочернего класса.
ASD_77 этого зачем-то хотел: там виртуальная функция для особо одаренных стоит что бы компелятор от с++ жидко обгадился когда начнет применять темплейты к фиртуальной функции
Может, специально придумывал искусственную задачу, где C++ напрямую не работает как C#.
using System;
namespace Rextester
{
public interface ICreator
{
T New<T>() where T : new();
}
public class Foo : ICreator
{
public T New<T>() where T : new()
{
////Console.WriteLine(typeof(T).Name);
return new T();
}
}
public class Program
{
public static void Run(ICreator creator)
{
var newString = creator.New<Foo>();
var newpituh = creator.New<Program>();
}
public static void Main(string[] args)
{
Run(new Foo());
}
}
}
свали в тюбик - раз программить не научился. Во первых 1) никто не заставляет компилить в ++ это раз. во вторых с# написанн та тех же с++/c и прекрасно все умеет делать
Прикол в том, что он хочет это делать через интерфейс. Т.е. совокупить единорога и лепрекона virtual и template в одном методе. Ясно, что в плюсах это (по крайней мере в стандарте) это невозможно.
С другой стороны сделать то, что он хочет, довольно просто с помощью паттерна из моего первого примера (aka "curiously recurring template pattern")
> по крайней мере в стандарте
Если учесть, что темплейт разворачивается (инстанциируется) только компилятором, и в рантайме инстанциированный темплейт это полноценный обособленный тип (или полноценная обособленная функция), которому в целом поебать, был ли он шаблонным когда-то, и кто его собратья и есть ли они вообще, при этом нет смысла хранить (мета?) код исходного темплейта - рантайму ничего с этим кодом не сделать, он не может и не должен в jit компиляцию какую-то, и новый код из xml или из сети он не сгенерит на лету (и тем более не прооптимизирует, не разберется со SFINAE, не найдет частичные специализации и т.д.) - то виртуальный шаблонный метод это оксюморон. Независимо от стандарта.
Для шарпо(и жабо)ёба интерфейс, походу, единственный контракт, о других они даже не слышали, им сложно принять то, что крестошаблон - это тоже контракт, как и то, что при развертывании кучи вложенных друг в друга шаблонов при обычных условиях компилятор выкинет к хуям информацию о всех промежуточных преобразованиях, получив только высокооптимизированный код, заточенный на конкретный тип.
Буквально недавно я генерил различные многомерные данные (статистика), которые беком должны были обернуться в 0-мерные (значение), 1-мерные (массив), 2-мерные (массив массивов), 3-мерные (...) структуры и отправиться на фронт для визуализации.
Что сделал жавоёб? Один тип для T, второй тип для List<T>, третий тип для List<List<T>>, четвертый для List<List<List<T>>>.
Помогли ему его интерфейсы с виртуальными генериками? Хуй там.
а ниче что когда компилятор компилить темлейт то он становиться конкретной специализацией. А если он стал специализацией то уже перестал быть темлейтом а значить "virtual" должен аплаиться. А компилятор не знает как 🙂
куда-куда аплаиться?
виртуальный означает, что потомок будет переопределять когда-нибудь с тем же контрактом (имя+параметры)
это когда-нибудь может возникнуть в другой длл спустя 10 лет
базовый класс не может предугадать как потомок будет инстанциировать этот метод
что он может сохранить для потомка в данном случае?
только исходный код или AST или ещё какой-нибудь питух-байт-ллвм-код, и в таблице виртуальных методов эти самие питух-коды вообще в отдельные места складывать, т.к. это не исполняемые точки входа
и все потомки, переопределяющие этот шаблон своим таким же шаблоном, должны заменять родительский питух-байткод своим
чтобы когда-нибудь jit компилятор смог в рантайме проинстанциировать эту метушню в валидные исполняемые инструкции
ну или смириться с тем, что <T> это просто сраный сахарок над Object, и контракт этой виртуальной функции именно что принимаем/возвращаем Object, ну или void * - и в этом случае вообще никаких оптимизаций (код предка уже скомпилирован в бинарном виде и неизменяем) и тем более специализаций, максимум, проверки компилятора о типе возвращенного объекта (ещё один сахарок)
почему копмилятор не подумал что референсить методы в таблице можно не только через целое положительное число. А например по кол-ву параметров или по sha256 от имени метода?
Каждый шаблонный метод в крестах раскрывается в свою имплементацию сразу, как только компилятор видит необходимость в этом. https://wandbox.org/permlink/N9ysRa2YhsT0d2SH
Затем все эти инстанциированные методы лягут в obj файл каждый под своим именем и адресом, чтобы линкер смог их в других модулях подставить в случае нужды.
Нет нужды в инстансе от, например, <char> - никто никакой код не сгенерит, и даже не подумает.
А в пределах единицы компиляции они вообще, скорее всего, заинлайнятся - тебе ведь обычно всё равно, являются ли они обособленными точками входа с каким то колл-конвеншеном, если тебе ни адреса не надо хранить, ничего, главное, чтобы они сделали "при вызове" то, что требуется. При инлайне компилятор их тело встроит в вызываемой код, перетасует, смешает с другими инструкциями, выкинет что-нибудь, и забудет, что это был шаблон какой-то какого-то класса foo, всё как обычно (для шарпера звучит диковато, понимаю).
Что именно ты собрался положить в ТВМ? Исходник шаблонного метода? Я об этом выше написал.
Т.к. спустя 10 лет я пишу свой тип MyAwesomeClass и инстанциирую им эту функцию, написанную кем-то 10 лет назад - какой код должен сгенерить компилятор за 10 лет до того, чтобы так заработало и потомком была найдена точка входа в подпрограмму foo::process<MyAwesomeClass>()?
1) проблема - С++ не разрешает использовать виртуальные темплейтные методы. Почему? потому что компилятор не может предугадать какие параметры темлейты могу быть использованны и поэтому не может сгенерировать __vtbl соответсвенно. А почему он не может это сделать? Ответ: потому что __vtbl распологает методы по порядку 0, 1, 2 в зависимости от того что в декларации класса написанно.
Но все это можно было бы избежать если бы методы в __vtbl референсились не по порядку как в декларации написанно а например по Hash code от имени функции, И тогда больше бы не было проблем с виртуальными темплейтными методами потому что "derived" класс всегда бы знал куда нужно положить метод в виртуальную таблицу.
т.е. не референсить по имени как делают dynamic языки а по hash - и все бы были довольны
virtual void process<int> и virtual void process<double> это две разные подпрограммы.
У них у каждой свои точки входа, у них у каждой свое тело, они даже вправе делать абсолютно своё, независимое друг от друга, и знать друг о друге не хотят.
При этом никакой точки входа у virtual void process<T> нет, т.к. в принципе нет никакого исполняемого кода, который олицетворял собой "неинстанциированный шаблон". Нет никаких машинных инструкций, не сохраняется никакого интермидиед-результата (там компилятор максимум AST может построить в процессе первого этапа разбора, проверить синтаксис - и то старые вижуал студии хуй забивали на двухэтапный разбор шаблона, проверяли только второй этап, в момент подстановки конкретного типа). В единице выполнения (exe, dll) шаблона нет. Есть только инстансы с конкретными типами. Всё. У них нет никакой семейственности. В исполняемой программе в режиме release нет никакого реестра созданных ей типов, ничего такого. Всё байты, даже небо, даже аллах. Исполняемый код - машинные инструкции под конкретную архитектуру/ОС/процессор.
В _vtbl должны лечь указатели на подпрограммы в качестве значения куда делать call/jmp.
Для метода process<T> никакого указателя нет. Для инстансов методов process<int> и process<double> свои указатели. Что класть в __vtbl? Какой из них может переопределить потомок? Что будет, если потомок захочет третий вариант инстанциированного шаблона? Какого объема рантайм нужно притащить в исполняемую единицу, чтобы имея исходный код шаблона (и всего, от чего он зависит) на лету сформировать ещё один метод, не хуже тех двух скомпилированных и прооптимизированных в процессе сборки? Кто будет заниматься поиском адресов функций, которые могут быть вызваны из такого генерирующегося метода в зависимости от текущего Т? А если там тоже шаблонные функции?
а ну да. так и есть. В этом и .опа что вызвать темлейт из виртуала нельзя. Но я больше думал про ситуацию когда все специализации темплейта уже известны. Но вот если юзать как либу и надо вызвать новую специализацию. Тогда без JITа никуда
с# generic не template поэтому он не может кастить T в другой тип если не знает какие значения может получать T
//Rextester.Program.Main is the entry point for your code. Don't change it.
//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5
using System;
using System.Collections.Generic;
namespace Rextester
{
public class base1 { };
public class class1 : base1 { };
public class class2 : base1 { };
public class Program
{
static int f<T>(T c) where T : base1 { return g(c); }
static int g(base1 c)
{
switch (c)
{
case class1 c1: return g(c1);
case class2 c2: return g(c2);
}
return 0;
}
static int g(class1 c) { return 1; }
static int g(class2 c) { return 2; }
public static void Main(string[] args)
{
//Your code goes here
Console.WriteLine(f((class1)null));
Console.WriteLine(f((class2)null));
}
}
}
вот ближайшая имплементация которая может работать
> он не может кастить T в другой тип
Темплейт ничего не кастит.
Он использует переданное точное значение типа вместо Т по всему своему коду для того, чтобы скомпилировать (не исполнить!) самостоятельный тип/функцию/метод, со всеми вытекающими (поэтому будет работать и вызов правильной перегруженной функции, и все остальное. А вот исходного шаблона никакого не останется.
угу. Согласен. Значит так надо юзать JIT. libjit уже есть. Но возникает вопрос. Нахрена тогда что-то юзать типа libjit есть уже есть c# & java? Ответ просто - потому что охота реюзать код на С++ например CryEngine а код писать на C# а рантайм юзать на андройде 🙂
<a href=http://cialis10mgprixenpharmacieenligne.com/>cialis 10mg cpr4 prix en pharmacie </a>
<a href=" http://cialis10mgprixenpharmacieenligne.com/ ">cialis 10mg prix en pharmacie en ligne </a>
<a href=http://cialis20mgprixenpharmacierx.com/>tadalafil 20mg prix </a>
<a href=" http://cialis20mgprixenpharmacierx.com/ ">cialis 20mg prix en pharmacie </a>
<a href=http://achetercialisenfrancesitefiable.com/>acheter cialis 20mg en france </a>
<a href=" http://achetercialisenfrancesitefiable.com/ ">acheter cialis generique en france </a>
<a href=http://achetercialissansordonnanceenpharmacie.c om/>acheter du cialis en france sans ordonnance </a>
<a href=" http://achetercialissansordonnanceenpharmacie.c om/ ">vente de cialis sans ordonnance en france </a>
<a href=http://achatcialisenfrancelivraisonrapide.com>a chat cialis en france livraison rapide </a>
<a href=" http://achatcialisenfrancelivraisonrapide.com ">acheter du cialis en ligne en france </a>
<a href=http://achatcialis5mgenligne.com/>achat cialis 5mg en ligne </a>
<a href=" http://achatcialis5mgenligne.com/ ">acheter cialis 5mg en ligne en france </a>
<a href=http://tadalafil20mgpaschereninde.com/>cialis tadalafil 20mg pas cher </a>
<a href=" http://tadalafil20mgpaschereninde.com/ ">tadalafil 20mg pas cher en inde </a>
<a href=http://achetertadalafilsansordonnance.com/>acheter tadalafil sans ordonnance </a>
<a href=" http://achetertadalafilsansordonnance.com/ ">peut on acheter du cialis sans ordonnance en france </a>
<a href=http://achattadalafilenfranceenpharmacie.com/>acheter cialis en france </a>
<a href=" http://achattadalafilenfranceenpharmacie.com/ ">achat cialis en ligne france </a>
<a href=http://acheterpropeciasurinternet.com/>acheter du propecia sur internet </a>
<a href=" http://acheterpropeciasurinternet.com/ ">acheter propecia sur internet </a>
> это когда-нибудь может возникнуть в другой длл спустя 10 лет
А если 10 лет назад кто-то скомпилирует указанный ниже класс, у нас при вызове A().method(Class2017()) будут проблемы?
class A {
template <typename T> void method(T) {}
};
Если будут, то это по сути та же ситуация, но только она допустима в C++, а значит спокойно можно было за счёт знания исходного кода в vtable нагенерить вореций для всех случаев.
можно явно инстанцировать шаблонных наследников базового класса, переопределяющих его виртуальные методы, спору нет. И можно в виртуальную функцию передавать какой-нибудь typeid, чтобы эта виртуальная функция могла работать с информацией о типе. Но придется всего-навсего явно инстанцировать специализации шаблона, для каждого типа, ручками.
Если выносить информацию о типах в рантайм можно вообще много какой метушни натворить. Вот только делать каждый инт наследником Object'а и инстанцировать его в хипе - не самый производительный сценарий, вы не находите?
п.с. именно поэтому студия аж 15 гигов весит (если уже не больше)
Иными словами, парочка #if с проверкой на компилятор/окружение должны решить вопрос c кросс-компиляторным demangle. Я почти уверен, что на GitHub (or whatever) уже можно найти рабочий код.
P.S. abi::__cxa_demangle дико бесит, что не constexpr. А ведь тип вполне себе известен на этапе компиляции. Такое ограничение не дает делать constexpr там, где надо получить имя типа...
Оператор, который генерирует литерал по имени типа. Что-то вида typeid.
Скажи это комитету
а ты часом не бароп?
И правильно сделает.
Что бы отменить что то, надо решить что то.
ну так скомпиляйте нам код. а мы посмотрим на него 🙂
Да, общий случай никто не предскажет и не запилит пацанский пирфоманс. Печально.
Покаж
Ибо генерик вообще не шаблон, это сахарок над Foo<Object>.
В крестах же напротив, шаблонный метод виртуальным не сделать.
раз две принципиально различные вещи для него должны быть сравнимы в категориях лучше-хуже
на балуйся.
ну тогда другой пример - template specialization:
если кококомпилятор c# сохраняет информацию о типах, и сам по себе язык обмазан сахаром в 10 слоев, что им помешало реализовать такую несложную вещь, как частичная/полная специализация?
ну или аналог крестушкового template <int N, int M> class Matrix()
раз уж так хочется сравнить несравнимое
интересно послушать
Если пишет Стертор, то там будет про хуи, педиков, собак, или прочей шизни
Пора бы уже научиться отличать меня.
такой dynamic cast даже в pl/sql есть, прости господи
а можно за O(0) всё таки - компилятор же знает о типе объекта, почему он не выбирает сразу правильную "перегрузку" из набора функций?
или про отсутствие type erasure маркетинговые презентации всё же немного подпёздывают?
в жабе тоже если чего-то нет, оно нахер не нужно
Ты ёбнулся?
там виртуальная функция для особо одаренных стоит что бы компелятор от с++ жидко обгадился когда начнет применять темплейты к фиртуальной функции
> делать не приходиться
> это бред - не говорят не люди не коты.
> что бы компелятор
> там виртуальная функция для особо одаренных стоит что бы компелятор от с++ жидко обгадился когда начнет применять темплейты к фиртуальной функции
Да это же вореционный бот, который своим кобенаторным алгоритмом осознал C++ до возможности написания своего буста, но русский язык учил по комментариям на Ютубе.
Static-C++ style. Ибо нефиг тут динамотой забавляться.
похоже надо самому строить __vtbl и вызывать через номер метода типа __vtbl[0]
А если WhoAmI(const std::type_info&) захочет распечатать само значение, дать ему ссылку на IPrinter, которую создавать в WhoAmI(const T &t), пока тип и значение известны.
https://wandbox.org/permlink/OPyDQMgGd2aKj8K0
там виртуальная функция для особо одаренных стоит что бы компелятор от с++ жидко обгадился когда начнет применять темплейты к фиртуальной функции
Может, специально придумывал искусственную задачу, где C++ напрямую не работает как C#.
а остальное в цппшник. И не надо инстанцировать никакой хуеты
напишите код который будет работать
Да можеш заюзать Boost::any 🙂
С другой стороны сделать то, что он хочет, довольно просто с помощью паттерна из моего первого примера (aka "curiously recurring template pattern")
Если учесть, что темплейт разворачивается (инстанциируется) только компилятором, и в рантайме инстанциированный темплейт это полноценный обособленный тип (или полноценная обособленная функция), которому в целом поебать, был ли он шаблонным когда-то, и кто его собратья и есть ли они вообще, при этом нет смысла хранить (мета?) код исходного темплейта - рантайму ничего с этим кодом не сделать, он не может и не должен в jit компиляцию какую-то, и новый код из xml или из сети он не сгенерит на лету (и тем более не прооптимизирует, не разберется со SFINAE, не найдет частичные специализации и т.д.) - то виртуальный шаблонный метод это оксюморон. Независимо от стандарта.
Для шарпо(и жабо)ёба интерфейс, походу, единственный контракт, о других они даже не слышали, им сложно принять то, что крестошаблон - это тоже контракт, как и то, что при развертывании кучи вложенных друг в друга шаблонов при обычных условиях компилятор выкинет к хуям информацию о всех промежуточных преобразованиях, получив только высокооптимизированный код, заточенный на конкретный тип.
Буквально недавно я генерил различные многомерные данные (статистика), которые беком должны были обернуться в 0-мерные (значение), 1-мерные (массив), 2-мерные (массив массивов), 3-мерные (...) структуры и отправиться на фронт для визуализации.
Что сделал жавоёб? Один тип для T, второй тип для List<T>, третий тип для List<List<T>>, четвертый для List<List<List<T>>>.
Помогли ему его интерфейсы с виртуальными генериками? Хуй там.
виртуальный означает, что потомок будет переопределять когда-нибудь с тем же контрактом (имя+параметры)
это когда-нибудь может возникнуть в другой длл спустя 10 лет
базовый класс не может предугадать как потомок будет инстанциировать этот метод
что он может сохранить для потомка в данном случае?
только исходный код или AST или ещё какой-нибудь питух-байт-ллвм-код, и в таблице виртуальных методов эти самие питух-коды вообще в отдельные места складывать, т.к. это не исполняемые точки входа
и все потомки, переопределяющие этот шаблон своим таким же шаблоном, должны заменять родительский питух-байткод своим
чтобы когда-нибудь jit компилятор смог в рантайме проинстанциировать эту метушню в валидные исполняемые инструкции
ну или смириться с тем, что <T> это просто сраный сахарок над Object, и контракт этой виртуальной функции именно что принимаем/возвращаем Object, ну или void * - и в этом случае вообще никаких оптимизаций (код предка уже скомпилирован в бинарном виде и неизменяем) и тем более специализаций, максимум, проверки компилятора о типе возвращенного объекта (ещё один сахарок)
Я всё ещё не пойму
Каждый шаблонный метод в крестах раскрывается в свою имплементацию сразу, как только компилятор видит необходимость в этом.
https://wandbox.org/permlink/N9ysRa2YhsT0d2SH
Затем все эти инстанциированные методы лягут в obj файл каждый под своим именем и адресом, чтобы линкер смог их в других модулях подставить в случае нужды.
Нет нужды в инстансе от, например, <char> - никто никакой код не сгенерит, и даже не подумает.
А в пределах единицы компиляции они вообще, скорее всего, заинлайнятся - тебе ведь обычно всё равно, являются ли они обособленными точками входа с каким то колл-конвеншеном, если тебе ни адреса не надо хранить, ничего, главное, чтобы они сделали "при вызове" то, что требуется. При инлайне компилятор их тело встроит в вызываемой код, перетасует, смешает с другими инструкциями, выкинет что-нибудь, и забудет, что это был шаблон какой-то какого-то класса foo, всё как обычно (для шарпера звучит диковато, понимаю).
Что именно ты собрался положить в ТВМ? Исходник шаблонного метода? Я об этом выше написал.
Т.к. спустя 10 лет я пишу свой тип MyAwesomeClass и инстанциирую им эту функцию, написанную кем-то 10 лет назад - какой код должен сгенерить компилятор за 10 лет до того, чтобы так заработало и потомком была найдена точка входа в подпрограмму foo::process<MyAwesomeClass>()?
1) проблема - С++ не разрешает использовать виртуальные темплейтные методы. Почему? потому что компилятор не может предугадать какие параметры темлейты могу быть использованны и поэтому не может сгенерировать __vtbl соответсвенно. А почему он не может это сделать? Ответ: потому что __vtbl распологает методы по порядку 0, 1, 2 в зависимости от того что в декларации класса написанно.
Но все это можно было бы избежать если бы методы в __vtbl референсились не по порядку как в декларации написанно а например по Hash code от имени функции, И тогда больше бы не было проблем с виртуальными темплейтными методами потому что "derived" класс всегда бы знал куда нужно положить метод в виртуальную таблицу.
т.е. не референсить по имени как делают dynamic языки а по hash - и все бы были довольны
virtual void process<int> и virtual void process<double> это две разные подпрограммы.
У них у каждой свои точки входа, у них у каждой свое тело, они даже вправе делать абсолютно своё, независимое друг от друга, и знать друг о друге не хотят.
При этом никакой точки входа у virtual void process<T> нет, т.к. в принципе нет никакого исполняемого кода, который олицетворял собой "неинстанциированный шаблон". Нет никаких машинных инструкций, не сохраняется никакого интермидиед-результата (там компилятор максимум AST может построить в процессе первого этапа разбора, проверить синтаксис - и то старые вижуал студии хуй забивали на двухэтапный разбор шаблона, проверяли только второй этап, в момент подстановки конкретного типа). В единице выполнения (exe, dll) шаблона нет. Есть только инстансы с конкретными типами. Всё. У них нет никакой семейственности. В исполняемой программе в режиме release нет никакого реестра созданных ей типов, ничего такого. Всё байты, даже небо, даже аллах. Исполняемый код - машинные инструкции под конкретную архитектуру/ОС/процессор.
В _vtbl должны лечь указатели на подпрограммы в качестве значения куда делать call/jmp.
Для метода process<T> никакого указателя нет. Для инстансов методов process<int> и process<double> свои указатели. Что класть в __vtbl? Какой из них может переопределить потомок? Что будет, если потомок захочет третий вариант инстанциированного шаблона? Какого объема рантайм нужно притащить в исполняемую единицу, чтобы имея исходный код шаблона (и всего, от чего он зависит) на лету сформировать ещё один метод, не хуже тех двух скомпилированных и прооптимизированных в процессе сборки? Кто будет заниматься поиском адресов функций, которые могут быть вызваны из такого генерирующегося метода в зависимости от текущего Т? А если там тоже шаблонные функции?
http://rextester.com/ZFW58650
вот ближайшая имплементация которая может работать
ну наконец-то, спасибо!
> он не может кастить T в другой тип
Темплейт ничего не кастит.
Он использует переданное точное значение типа вместо Т по всему своему коду для того, чтобы скомпилировать (не исполнить!) самостоятельный тип/функцию/метод, со всеми вытекающими (поэтому будет работать и вызов правильной перегруженной функции, и все остальное. А вот исходного шаблона никакого не останется.
У меня всё.
<a href=" http://cialis10mgprixenpharmacieenligne.com/ ">cialis 10mg prix en pharmacie en ligne </a>
<a href=" http://cialis20mgprixenpharmacierx.com/ ">cialis 20mg prix en pharmacie </a>
<a href=" http://achetercialisenfrancesitefiable.com/ ">acheter cialis generique en france </a>
<a href=" http://achetercialissansordonnanceenpharmacie.c om/ ">vente de cialis sans ordonnance en france </a>
<a href=" http://achatcialisenfrancelivraisonrapide.com ">acheter du cialis en ligne en france </a>
<a href=" http://achatcialis5mgenligne.com/ ">acheter cialis 5mg en ligne en france </a>
<a href=" http://tadalafil20mgpaschereninde.com/ ">tadalafil 20mg pas cher en inde </a>
<a href=" http://achetertadalafilsansordonnance.com/ ">peut on acheter du cialis sans ordonnance en france </a>
<a href=" http://achattadalafilenfranceenpharmacie.com/ ">achat cialis en ligne france </a>
<a href=" http://acheterprednisone20mgenligne.com/ ">acheter prednisone 20 mg en ligne </a>
<a href=" http://acheterpropeciasurinternet.com/ ">acheter propecia sur internet </a>
<a href=" http://achatamoxicillinebiogaran1g.com/ ">acheter amoxicilline 1g en ligne </a>
А если 10 лет назад кто-то скомпилирует указанный ниже класс, у нас при вызове A().method(Class2017()) будут проблемы?
Если будут, то это по сути та же ситуация, но только она допустима в C++, а значит спокойно можно было за счёт знания исходного кода в vtable нагенерить вореций для всех случаев.
Если выносить информацию о типах в рантайм можно вообще много какой метушни натворить. Вот только делать каждый инт наследником Object'а и инстанцировать его в хипе - не самый производительный сценарий, вы не находите?
п.с. именно поэтому студия аж 15 гигов весит (если уже не больше)