// Основной класс
class Test
{
public:
// Шаблонный конструктор
// принимает параметр типа, который определяется ParamTraits
template<typename Type>
Test(typename ParamTraits<Type>::ParamType param);
};
При компиляции инстанциирования компилятор (msvc7.1) 3 раза (для каждого инстанциирования) выдаёт:
error C2945: explicit instantiation does not refer to a template-class specialization
error C3190: 'Test::Test(ParamTraits<Type>::ParamType)' with the provided template arguments is not the explicit instantiation of any member function of 'Test'
Здравствуйте, remark, Вы писали:
R>// Инстанциирование R>#define INSTANTIATE_TEST(Type) template Test::Test(ParamTraits<Type>::ParamType)
R>INSTANTIATE_TEST(int); R>INSTANTIATE_TEST(long); R>INSTANTIATE_TEST(std::string);
В твоем коде тип Type невозможно вывести из ParamTraits<Type>::ParamType. Поэтому макрос INSTANTIATE_TEST должен был бы выглядеть так:
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Глеб Алексеев, Вы писали:
ГА>>В твоем коде тип Type невозможно вывести из ParamTraits<Type>::ParamType.
R>На сколько я заню и вижу, тип параметра тут можно вывести. Такой код работает:
Здравствуйте, Глеб Алексеев, Вы писали:
ГА>Но! Не тут-то было. У ВЦ 7.1, как оказалось благодаря твоему вопросу ( ), проблемы с явным инстанцированием конструкторов:
И не только у него. GCC 3.4.2 (и 4.0 также) плохо реагирует на явное инстанцирование конструктора, когда тип указывается явно:
class A
{
public:
template <typename Type>
A(Type ) {}
template <typename Type>
void foo(Type ) {}
};
template A::A(int ); // Вот так все ОКtemplate A::A<long>(long ); // А вот так уже плохо.
// А здесь всегда все хорошоtemplate void A::foo(int );
template void A::foo<long>(long );
На высоте себя показали Intel C++ и Comeau — оба ведут себя хорошо.
Нет, в первоначальном варианте использовалось dependent name ParamTraits<Type>::ParamType, а по нему правильный ParamTraits автоматически вывести нельзя.
Здравствуйте, swamper, Вы писали:
>>> Здравствуйте, remark, Вы писали:
S>А зачем нужно инстанцирование? Не совсем понятно, какой от этого будет толк. S>Тем не менее, вот пример кода, который инстанцирует шаблонную функцию:
S>
Интересный вариант. Не делать явное инстанциирование, а заставить компилятор инстанциировать.
Тут есть ограничение, что ParamTraits<Type>::ParamType должен иметь конструктор по-умолчанию, но в моём случае, это не страшно.
Хотя так всё равно не работает. Компилятор не инстанциирует шаблон.
Я написал что-то вроде этого:
Здравствуйте, CrystaX, Вы писали:
CX>Здравствуйте, remark, Вы писали:
R>>На сколько я заню и вижу, тип параметра тут можно вывести. Такой код работает:
R>>
CX>Нет, в первоначальном варианте использовалось dependent name ParamTraits<Type>::ParamType, а по нему правильный ParamTraits автоматически вывести нельзя.
Вывести надо Type, а не ParamType. Хотя я тут не очень силён.
Ну ладно, это не важно. Всё равно решения не получается.
Здравствуйте, __LP, Вы писали:
__L>Здравствуйте, remark, Вы писали:
R>>Здравствуйте, Глеб Алексеев, Вы писали:
ГА>>>В твоем коде тип Type невозможно вывести из ParamTraits<Type>::ParamType.
R>>На сколько я заню и вижу, тип параметра тут можно вывести. Такой код работает:
Здравствуйте, remark, Вы писали:
R>Вывести надо Type, а не ParamType. Хотя я тут не очень силён. R>Ну ладно, это не важно. Всё равно решения не получается.
Хмм... Так тебе ParamTraits не нужен в конструкторе? Тогда может так подойдет:
// Основной классclass Test
{
public:
// Шаблонный конструктор
// принимает параметр типа, который определяется ParamTraitstemplate<typename Type>
Test(Type param);
};
// Реализация конструктораtemplate<typename Type>
Test::Test(Type param)
{
// ...
}
// Инстанциирование#define INSTANTIATE_TEST(Type) template Test::Test(ParamTraits<Type>::ParamType)
INSTANTIATE_TEST(int);
INSTANTIATE_TEST(long);
INSTANTIATE_TEST(std::string);
Здравствуйте, CrystaX, Вы писали:
CX>Здравствуйте, remark, Вы писали:
R>>Вывести надо Type, а не ParamType. Хотя я тут не очень силён. R>>Ну ладно, это не важно. Всё равно решения не получается.
CX>Хмм... Так тебе ParamTraits не нужен в конструкторе? Тогда может так подойдет:
Нет, он мне нужен, и именно в конструкторе.
Если быть более точным, то пример примерно такой:
// Структура задаёт тип параметра, который принимает конструкторtemplate<typename Type>
struct ParamTraits
{
typedef Type1 ParamType1;
typedef Type2 ParamType2;
typedef Type3 ParamType3;
};
// Основной классclass Test
{
public:
// Шаблонный конструктор
// принимает параметр типа, который определяется ParamTraitstemplate<typename Type>
Test(int, typename ParamTraits<Type>::ParamType1 param1, typename ParamTraits<Type>::ParamType2 param2, typename ParamTraits<Type>::ParamType3 param3);
};
Здравствуйте, remark, Вы писали:
R>Здравствуйте, swamper, Вы писали:
>>>> Здравствуйте, remark, Вы писали:
S>>А зачем нужно инстанцирование? Не совсем понятно, какой от этого будет толк. S>>Тем не менее, вот пример кода, который инстанцирует шаблонную функцию:
S>>
R>Интересный вариант. Не делать явное инстанциирование, а заставить компилятор инстанциировать. R>Тут есть ограничение, что ParamTraits<Type>::ParamType должен иметь конструктор по-умолчанию, но в моём случае, это не страшно.
R>Хотя так всё равно не работает. Компилятор не инстанциирует шаблон. R>Я написал что-то вроде этого:
R>
Здравствуйте, remark, Вы писали:
R>Но, при компиляции:
R>
R>Test test(10);
R>
R>ругается:
R>error C2664: 'Test::Test(const Test &)' : cannot convert parameter 1 from 'int' to 'const Test &'
Заметь, ты получишь эту ошибку, даже если определение шаблона будет видимо. Т.е. к явному инстанцированию шаблона это отношенипя не имеет.
Дело в том, что в твоем коде агрумент шаблона из типа аргумента не выводится, как уже сказали раза 4. Следовательно, этот конструктор ты просто не сможешь вызвать, не добавив к нему dummy-аргументов.
А у VC все действительно оказалось еще более запущено, чем я думал, следующий легальный код компилить отказывается:
Но чего мы добились? Объекты A теперь приходится создавать так:
A a1(0, (int*)0);
A a1(false, (bool*)0);
Как уже сказано, это не имеет отношения к явному инстанцированию конструкторов, проблема вызвана невозможностью вывести тип аргумента шаблона — компилятор не знает, какой конструктор вызвать, его приходится тыкать носом, что неудобно (дать указателю dummy значение =0 по умолчанию мы не можем по этой же причине).
ИМХО, если ты все равно собираешься явно перечислять все типы, для которых данный конструктор может быть вызван (иначе зачем явное инстанцирование?), то почему не облегчить жизнь себе и другим, просто перегрузив конструкторы для всех нужных типов? А реализация этих конструкторов уже может использовать любые злые шаблоны, какие только душе угодны.
Здравствуйте, Глеб Алексеев, Вы писали:
ГА>Здравствуйте, remark, Вы писали:
R>>Но, при компиляции:
R>>
R>>Test test(10);
R>>
R>>ругается:
R>>error C2664: 'Test::Test(const Test &)' : cannot convert parameter 1 from 'int' to 'const Test &'
ГА>Заметь, ты получишь эту ошибку, даже если определение шаблона будет видимо. Т.е. к явному инстанцированию шаблона это отношенипя не имеет. ГА>Дело в том, что в твоем коде агрумент шаблона из типа аргумента не выводится, как уже сказали раза 4. Следовательно, этот конструктор ты просто не сможешь вызвать, не добавив к нему dummy-аргументов.
ГА>А у VC все действительно оказалось еще более запущено, чем я думал, следующий легальный код компилить отказывается: ГА>
ГА>Как уже сказано, это не имеет отношения к явному инстанцированию конструкторов, проблема вызвана невозможностью вывести тип аргумента шаблона — компилятор не знает, какой конструктор вызвать, его приходится тыкать носом, что неудобно (дать указателю dummy значение =0 по умолчанию мы не можем по этой же причине).
ГА>ИМХО, если ты все равно собираешься явно перечислять все типы, для которых данный конструктор может быть вызван (иначе зачем явное инстанцирование?), то почему не облегчить жизнь себе и другим, просто перегрузив конструкторы для всех нужных типов? А реализация этих конструкторов уже может использовать любые злые шаблоны, какие только душе угодны.
Я хотел как раз от этого уйти
У меня по 6 конструкторов для 10 типов... Раньше было сделано с помощью макросов. Всё таки от макросов не уйти
Всё таки если без шаблонов, то во-первых, будут макросы, чего хотелось бы избежать (в данном случае ещё мешает дебажить), во-вторых, будет значительное дублирование кода — даже если в этих конструкторах будет по одной строчке, менять их все вместе геморойно.
Здравствуйте, Глеб Алексеев, Вы писали:
ГА>Здравствуйте, remark, Вы писали:
R>>Но, при компиляции:
R>>
R>>Test test(10);
R>>
R>>ругается:
R>>error C2664: 'Test::Test(const Test &)' : cannot convert parameter 1 from 'int' to 'const Test &'
ГА>Заметь, ты получишь эту ошибку, даже если определение шаблона будет видимо. Т.е. к явному инстанцированию шаблона это отношенипя не имеет. ГА>Дело в том, что в твоем коде агрумент шаблона из типа аргумента не выводится, как уже сказали раза 4. Следовательно, этот конструктор ты просто не сможешь вызвать, не добавив к нему dummy-аргументов.
Аааа... Вы всё имеете в виду, что он не выводиться при вызове конструктора, меня пока волнует почему ошибка в строчке, где я явно инстанциирую шаблон:
Здравствуйте, remark, Вы писали:
R>Аааа... Вы всё имеете в виду, что он не выводиться при вызове конструктора, меня пока волнует почему ошибка в строчке, где я явно инстанциирую шаблон:
Так это же вроде уже выяснили. Глюк VC, Комо замечательно компилит явное инстанцирование конструкторов независимо от выводимости аргументов шаблона. Остальное относилось к тому, что все обходные пути того не стоят, т.к. вызвать нужный конструктор все равно не получится, если аргументы шаблона не выводятся, даже на идеальном компиляторе.
Здравствуйте, Глеб Алексеев, Вы писали:
ГА>Здравствуйте, remark, Вы писали:
R>>Аааа... Вы всё имеете в виду, что он не выводиться при вызове конструктора, меня пока волнует почему ошибка в строчке, где я явно инстанциирую шаблон: ГА>Так это же вроде уже выяснили. Глюк VC, Комо замечательно компилит явное инстанцирование конструкторов независимо от выводимости аргументов шаблона. Остальное относилось к тому, что все обходные пути того не стоят, т.к. вызвать нужный конструктор все равно не получится, если аргументы шаблона не выводятся, даже на идеальном компиляторе.
Хорошо, понял.
А если изменить условия, т.ч. первый аргумент конструктора всегда int, второй — всегда Type (сам параметр шаблона), а второй через traits, т.е. так сказать сдвинуть точку отсчёта в первый шаблонный параметр.
template<typename Type>
Test(int, Type type, typename ParamTraits<Type>::ParamType param);
Здравствуйте, remark, Вы писали:
R>Нет, он мне нужен, и именно в конструкторе.
Выходит, что тебе все-таки нужен ParamTraits, а вывести его из зависимого имени ParamType не получится. Поэтому его надо указывать явно.
R>Если быть более точным, то пример примерно такой:
R>
R>// Структура задаёт тип параметра, который принимает конструктор
R>template<typename Type>
R>struct ParamTraits
R>{
R> typedef Type1 ParamType1;
R> typedef Type2 ParamType2;
R> typedef Type3 ParamType3;
R>};
R>// Основной класс
R>class Test
R>{
R>public:
R> // Шаблонный конструктор
R> // принимает параметр типа, который определяется ParamTraits
R> template<typename Type>
R> Test(int, typename ParamTraits<Type>::ParamType1 param1, typename ParamTraits<Type>::ParamType2 param2, typename ParamTraits<Type>::ParamType3 param3);
R>};
R>
R>И без TypeTraits тут сделать не получается.
Я не совсем понимаю. Зачем здесь ParamTraits? Для автоматического выведения типа? Так это в любом случае не получится. Или еще для чего?
Здравствуйте, CrystaX, Вы писали:
CX>Здравствуйте, remark, Вы писали:
R>>Нет, он мне нужен, и именно в конструкторе.
CX>Выходит, что тебе все-таки нужен ParamTraits, а вывести его из зависимого имени ParamType не получится. Поэтому его надо указывать явно.
R>>Если быть более точным, то пример примерно такой:
R>>
R>>// Структура задаёт тип параметра, который принимает конструктор
R>>template<typename Type>
R>>struct ParamTraits
R>>{
R>> typedef Type1 ParamType1;
R>> typedef Type2 ParamType2;
R>> typedef Type3 ParamType3;
R>>};
R>>// Основной класс
R>>class Test
R>>{
R>>public:
R>> // Шаблонный конструктор
R>> // принимает параметр типа, который определяется ParamTraits
R>> template<typename Type>
R>> Test(int, typename ParamTraits<Type>::ParamType1 param1, typename ParamTraits<Type>::ParamType2 param2, typename ParamTraits<Type>::ParamType3 param3);
R>>};
R>>
R>>И без TypeTraits тут сделать не получается.
CX>Я не совсем понимаю. Зачем здесь ParamTraits? Для автоматического выведения типа? Так это в любом случае не получится. Или еще для чего?
ParamTraits используется собственно по прямому назначению нужны разные наборы типов для параметров конструктора. А именно, например:
Здравствуйте, Глеб Алексеев, Вы писали:
ГА>Так это же вроде уже выяснили. Глюк VC, Комо замечательно компилит явное инстанцирование конструкторов независимо от выводимости аргументов шаблона.
Не совсем так. В случае, если типы невыводимы из аргументов, Комо выдает ошибку. Первоначальный пример он не компилирует. Но если изменить шаблон INSTANTIATE_TEST, указав явно тип, с которым нужно инстанцировать, все пройдет на ура. К сожалению, VC 7.1 содержит баг, заключающийся в том, что явное инстанцирование шаблонов конструкторов он не производит при явном указании типа.
#define INSTANTIATE_TEST(Type) template Test::Test(ParamTraits<Type>::ParamType) // Так неверно#define INSTANTIATE_TEST(Type) template Test::Test<Type>(ParamTraits<Type>::ParamType) // А вот так все ОК, но не для VC 7.1
Здравствуйте, remark, Вы писали:
R>Хорошо, понял. R>А если изменить условия, т.ч. первый аргумент конструктора всегда int, второй — всегда Type (сам параметр шаблона), а второй через traits, т.е. так сказать сдвинуть точку отсчёта в первый шаблонный параметр.
R>
Получится, но опять через ..гм, Амстердам, т.к. VC и в этом случае будет глючить при попытке явно инстанцировать, нужно идти в обход (варианты уже предлагались).
Сделай проще:
#include <string>
template <class T>
struct traits {
typedef T type;
};
template <>
struct traits<std::string> {
typedef const std::string& type;
};
struct A {
template <class T, class P>
A(T t, P p /* раньше вместо P был typename traits<T>::type */) {
}
};
template A::A(std::string, traits<std::string>::type);
template A::A(int, traits<int>::type);
Не страшно, что типы T и P в объявлении конструктора никак не связаны, т.к. он инстанцируется явно и допустимые типы все равно под твоим контролем (правда, диагностика ошибок сдвинется на фазу компоновки).
Здравствуйте, CrystaX, Вы писали:
ГА>>Так это же вроде уже выяснили. Глюк VC, Комо замечательно компилит явное инстанцирование конструкторов независимо от выводимости аргументов шаблона. CX>Не совсем так. В случае, если типы невыводимы из аргументов, Комо выдает ошибку. Первоначальный пример он не компилирует. Но если изменить шаблон INSTANTIATE_TEST, указав явно тип, с которым нужно инстанцировать, все пройдет на ура. К сожалению, VC 7.1 содержит баг, заключающийся в том, что явное инстанцирование шаблонов конструкторов он не производит при явном указании типа. CX>
CX>#define INSTANTIATE_TEST(Type) template Test::Test(ParamTraits<Type>::ParamType) // Так неверно
CX>#define INSTANTIATE_TEST(Type) template Test::Test<Type>(ParamTraits<Type>::ParamType) // А вот так все ОК, но не для VC 7.1
CX>
Я имел в виду, что Комо справляется со вторым случаем.
Все равно не понимаю, какие из этого выгоды. У тебя что, во всех случаях одно и то же тело конструктора? Или все-таки разное? И еще — каким образом в данной ситуации может помочь явное инстанцирование?
CX>Все равно не понимаю, какие из этого выгоды. У тебя что, во всех случаях одно и то же тело конструктора?
А что такого? Нельзя?
Да, тело одинаковое и шаблонное, т.е. в нём тоже вызываются шаблонные функции.
CX>Или все-таки разное? И еще — каким образом в данной ситуации может помочь явное инстанцирование?
Явное инстанциирование нужно, что бы не было модели включения, что бы компилировать в каждом файле кучу шаблонов, + типы для которых надо инстанциировать известны и фиксированы + это всё будет в библиотеке .lib
Здравствуйте, Глеб Алексеев, Вы писали:
ГА>Здравствуйте, remark, Вы писали:
R>>Хорошо, понял. R>>А если изменить условия, т.ч. первый аргумент конструктора всегда int, второй — всегда Type (сам параметр шаблона), а второй через traits, т.е. так сказать сдвинуть точку отсчёта в первый шаблонный параметр.
R>>
R>>Так получиться?
ГА>Получится, но опять через ..гм, Амстердам, т.к. VC и в этом случае будет глючить при попытке явно инстанцировать, нужно идти в обход (варианты уже предлагались). ГА>Сделай проще:
...
ГА>Не страшно, что типы T и P в объявлении конструктора никак не связаны, т.к. он инстанцируется явно и допустимые типы все равно под твоим контролем (правда, диагностика ошибок сдвинется на фазу компоновки).
Ясно. Спасибо. Вариант хороший. Значит всё-таки это msvc глючит...
Правда речь идёт о классе из библиотеки. Пока это выглядело как:
Здравствуйте, remark, Вы писали:
R>А что такого? Нельзя? R>Да, тело одинаковое и шаблонное, т.е. в нём тоже вызываются шаблонные функции.
Можно. Но у меня сложилось впечатление, что тело разное.
CX>>Или все-таки разное? И еще — каким образом в данной ситуации может помочь явное инстанцирование?
R>Явное инстанциирование нужно, что бы не было модели включения, что бы компилировать в каждом файле кучу шаблонов, + типы для которых надо инстанциировать известны и фиксированы + это всё будет в библиотеке .lib
Ну это-то понятно. Просто показалось, что ты таким образом пытаешься наложить определенные ограничения compile- и/или link-time.
Вот здесь ты противоречишь сам себе. Недавно ты говорил, что перегрузок конструкторов для всех типов параметров нет, точнее, ты хочешь от них избавиться.
Кроме того, для среднего пользователя
template <class T, class P>
A(T& value , P default);
В любом случае, сам шаблонный конструктор вида template <class T, class P> A(...) можно перенести в закрытый базовый класс, а в интерфейсной части библиотеки использовать либо множество перегруженных конструкторов, либо вариант с traits. Как-нибудь так:
Здравствуйте, Глеб Алексеев, Вы писали:
ГА>Вот здесь ты противоречишь сам себе. Недавно ты говорил, что перегрузок конструкторов для всех типов параметров нет, точнее, ты хочешь от них избавиться.
Да так и есть. Не понял.
ГА>Кроме того, для среднего пользователя ГА>
Здравствуйте, remark, Вы писали:
ГА>>Вот здесь ты противоречишь сам себе. Недавно ты говорил, что перегрузок конструкторов для всех типов параметров нет, точнее, ты хочешь от них избавиться. R>Да так и есть. Не понял.
Разве ты не говорил: R>Правда речь идёт о классе из библиотеки. Пока это выглядело как:
R>Было всё достаточно понятно,
?
R>Согласен. Надо просто их переназвать — не T и P, а типа ValueType и ReferenceType.
Тогда уж не ReferenceType, а ArgumentType.
А еще лучше сделать так, как я предложил (с базовым классом), тогда еще и диагностика на стадии компиляции будет.
Здравствуйте, Глеб Алексеев, Вы писали:
ГА>Здравствуйте, remark, Вы писали:
ГА>>>Вот здесь ты противоречишь сам себе. Недавно ты говорил, что перегрузок конструкторов для всех типов параметров нет, точнее, ты хочешь от них избавиться. R>>Да так и есть. Не понял.
ГА>Разве ты не говорил: R>>Правда речь идёт о классе из библиотеки. Пока это выглядело как: ГА>
ГА>В любом случае, сам шаблонный конструктор вида template <class T, class P> A(...) можно перенести в закрытый базовый класс, а в интерфейсной части библиотеки использовать либо множество перегруженных конструкторов, либо вариант с traits. Как-нибудь так: ГА>
идея тоже интересная.
Я всё-таки решил в итоге делать немного подругому:
Т.к. это один из основных классов, который торчит из библиотеки, я всё-таки вручную (через макросы) записал все возможные конструкторы. А в реализации (которая тоже сделана с помощью макросов) сразу же (в одну строчку) перенаправляю логику во внутреннюю шаблонную часть.
Здравствуйте, remark, Вы писали:
R>Я всё-таки решил в итоге делать немного подругому: R>Т.к. это один из основных классов, который торчит из библиотеки, я всё-таки вручную (через макросы) записал все возможные конструкторы. А в реализации (которая тоже сделана с помощью макросов) сразу же (в одну строчку) перенаправляю логику во внутреннюю шаблонную часть.
Ну что же... Бывает, от макросов не уйти... Не зная предметной области, трудно посоветовать что-либо конкретное.
R>
А вот с этим согласен.