Интересно, а есть какая-то «статистика», сколько человек/процентов использует C++/CLI как основной язык? Вы же не просто эту возможность сделали «чтобы было»?
Илья Ковалевский — прошлогодний победитель; Benjamin Kaiser — поступил в университет в 14 лет, написал 2 приложения для iPhone; Levente Kurusa — имеет 6 патчей в ядре Linux за 2014 год;
Т.е. Вы просто указываете полную сигнатуру метода + возвращаемый тип. Удобно в том плане, что различие между этим и действительным объявлением метода в классе — только 2 запятые.
Кстати, я пошёл дальше и ради интереса — а можно ли узнать о методе, если он шаблонный?
И, всё работает, только не со студией:) 3й рядок не компилируется с ошибкой «An internal error has occurred in the compiler».
vc++(13 студия, Microsoft ® C/C++ Optimizing Compiler Version 18.00.21005.1 for x86): результат;
gcc(g++ 4.8.1 (g++ -Wall -std=c++11 -O2)): результат;
clang(clang 3.4 (clang++ -Wall -std=c++11 -O2)): результат;
Да, кстати, может поздно и не важно, но статья действительно хорошая(как и реализация) и у меня возник вопрос ещё тогда по поводу FinalizeConstruct /BeforeRelease. Может, это смешно, но всё таки спрошу — почему не сделать что-то типа такого макроса для проверки есть ли метод в классе ?:
Попроще, чем у ilammy. Можно сделать так. Основной костяк:
// Делается по "накатанной" схеме - определяем основу шаблона.
// В этом случае шаблон инстанцируется для
// - любого другого шаблонного класса, который имеет один параметр(<b>Caller</b>)
// - любого другого типа(<b>TL</b>)
template<template<typename> class Caller, typename TL>
struct ForEach
{
};
// Дальше - уточняем - на самом деле мы хотим иметь только:
// - любой другой шаблонный класса, как первый аргумент(<b>Caller</b>)
// - именно какую-то версию <b>TypeList</b>, как другой аргумент
template<template<typename> class Caller, typename ...Args>
struct ForEach<Caller, TypeList<Args...>>
{
typedef TypeList<Args...> TL;
void operator()() const
{
// Для Caller<T> - должен быть перегружен operator(),
// где T - это TL::Head. Можно выбрать и любую другую ф-ю.
Caller<typename TL::Head>()();
// Рекурсия - вызываем всё то же для хвоста
ForEach<Caller, typename TL::Tail>()();
}
};
// Говорим, что когда список типов пуст - ничего не делать
template<template<typename> class Caller>
struct ForEach<Caller, EmptyTypeList>
{
void operator()() const
{
}
};
Всё, теперь определяем наш «функтор» — по сути тело цикла для каждого типа T:
// Для любого типа
template<typename T>
struct Call
{
void operator()() const
{
std::cout << typeid(T).name() << std::endl;
}
};
// Делаем полную специализацию шаблона для 'float', допустим
template<>
struct Call<float>
{
void operator()() const
{
std::cout << "Call<float>" << std::endl;
}
};
Извините, но я немножко не понял концепцию. Обычно, ведь, каждый параметр шаблона, в таких случаях, отвечает за некоторое свойство(которое имеет ряд значений). Например, boost::transform_iterator:
template <class UnaryFunction,
class Iterator,
class Reference = use_default,
class Value = use_default>
class transform_iterator
Reference отвечает за член класса reference и, выставляя Reference, мы управляем «свойством» reference и т.д. И порядок имеет значение — чтобы выставить reference, мы задаём его значение 3м аргументом. Как Вы и сказали:
Но мы прекрасно понимаем, что как только мы поменяли два параметр у нас получится совершенно не то чего мы ожидали
А чтобы всё работало в случае с произвольным порядком нужно иметь «договорённость»: это «свойство» (параметр шаблона) имеет ряд конкретных значений(типов): 1, 2, 3. Другое свойство имеет другой набор: 4, 5, 6. Причём значения не должны совпадать(т.е. типы должны не совпадать, кроме как «значения по-умолчанию»). Я правильно понимаю? А это не усложняет всё? Не ограничивает?
UPD: если я правильно понял, то как раз это Вы и написали:
Способ который я хочу показать не позволяет специализировать шаблон произвольным типом.
Не уверен, но вот мне интересно его мнение о WinRT и WinAPI32: по сути — противоположные в плане реализации вещи: WinAPI — C, WinRT — тут тебе и С++, и COM, который все похоронили перед этим. Будет ли он писать что-то о WinRT, аналогичное его «Windows Via C/C++»? Что он думает о metro-приложениях — писать нужно используя WinRT, а WinAPI доступно не полностью, а в случае с ARM — WinAPI вообще нет?
Ну не хочется таскать с собой буст постоянно, при попытке иметь малейшие «удобства», которые должны поддерживаться компилятором(библиотекой) по стандарту. Например, тот fuction, который был в ::std::tr1 совсем не работал и постоянно падал с ассертами где-то внутри. И постоянно подключать буст только из-за этого — не очень приятно. Так что — молодцы — работают!
Извините за оффтоп, но подскажите, может есть возможность постройки 3D графика из набора точек ({x, y, z})? Потому-что меня не устраивает задавать функцию z = f(x, y), а только такой способ я и нашёл в Qwt.
Компилятор сделает срез базового типа по отнаследованному. И если указатель увеличился с 1, значит объект был срезан.
Можете поподробней рассказать вот это место:
И если указатель увеличился с 1, значит объект был срезан
У вас же Message — полиморфный и вы передаёте его по ссылке, можно восстановить объект. Как-то так:
struct A
{
int a_;
A(int a)
: a_(a)
{
}
virtual ~A()
{
}
};
struct B :
public A
{
int b_;
B(int a, int b)
: A(a)
, b_(b)
{
}
};
struct C :
public A
{
int c_;
C(int a, int c)
: A(a)
, c_(c)
{
}
};
void test(const A& a)
{
try
{
const B& b = dynamic_cast<const B&>(a);
std::cout << b.a_ << " " << b.b_ << std::endl;
}
catch(const std::bad_cast& e)
{
std::cout << "test: @a is not B: " << e.what() << std::endl;
}
}
int main()
{
test(C(10, 20));
test(B(10, 30));
return 0;
}
Об этом(как-то «ограничения на типы» или что-то в этом роде), кстати, Страуструп писал в «Дизайн и эволюция C++». И это в 90тые годы — не помню, какие доводы были за и против.
«Вау, да Вы с ума сошли!».
Огромная работа, как по мне.
Жесть. Поздравляю!
А по поводу const, volatile:
Т.е. Вы просто указываете полную сигнатуру метода + возвращаемый тип. Удобно в том плане, что различие между этим и действительным объявлением метода в классе — только 2 запятые.
Кстати, я пошёл дальше и ради интереса — а можно ли узнать о методе, если он шаблонный?
И, всё работает, только не со студией:) 3й рядок не компилируется с ошибкой «An internal error has occurred in the compiler».
vc++(13 студия, Microsoft ® C/C++ Optimizing Compiler Version 18.00.21005.1 for x86): результат;
gcc(g++ 4.8.1 (g++ -Wall -std=c++11 -O2)): результат;
clang(clang 3.4 (clang++ -Wall -std=c++11 -O2)): результат;
На всякий случай — зарепортил
Всё, теперь определяем наш «функтор» — по сути тело цикла для каждого типа
T
:Используем:
Результат:
и т.д.
Спасибо за пример
boost::transform_iterator
:Reference
отвечает за член классаreference
и, выставляяReference
, мы управляем «свойством»reference
и т.д. И порядок имеет значение — чтобы выставитьreference
, мы задаём его значение 3м аргументом. Как Вы и сказали:А чтобы всё работало в случае с произвольным порядком нужно иметь «договорённость»: это «свойство» (параметр шаблона) имеет ряд конкретных значений(типов): 1, 2, 3. Другое свойство имеет другой набор: 4, 5, 6. Причём значения не должны совпадать(т.е. типы должны не совпадать, кроме как «значения по-умолчанию»). Я правильно понимаю? А это не усложняет всё? Не ограничивает?
UPD: если я правильно понял, то как раз это Вы и написали:
fuction
, который был в::std::tr1
совсем не работал и постоянно падал с ассертами где-то внутри. И постоянно подключать буст только из-за этого — не очень приятно. Так что — молодцы — работают!3D
графика из набора точек ({x, y, z}
)? Потому-что меня не устраивает задавать функциюz = f(x, y)
, а только такой способ я и нашёл вQwt
.Можете поподробней рассказать вот это место:
У вас же
Message
— полиморфный и вы передаёте его по ссылке, можно восстановить объект. Как-то так:Вывод:
test: @a is not B: Bad dynamic_cast!
10 30