All streams
Search
Write a publication
Pull to refresh
31
0

User

Send message
Интересно, а есть какая-то «статистика», сколько человек/процентов использует C++/CLI как основной язык? Вы же не просто эту возможность сделали «чтобы было»?
Я не читал эту статью, но реакция на заголовок:
«Вау, да Вы с ума сошли!».
Огромная работа, как по мне.
echo -------------------------------------- 
echo ---------- .:: -=LEXX=- ::. ----------
echo -------------------------------------- 
Илья Ковалевский — прошлогодний победитель; Benjamin Kaiser — поступил в университет в 14 лет, написал 2 приложения для iPhone; Levente Kurusa — имеет 6 патчей в ядре Linux за 2014 год;

Жесть. Поздравляю!
Да, забыл добавить, что с 10й студией — компилируется, но выдаёт неправильный результат(0 вместо 1)
Спасибо за ответ.
А по поводу const, volatile:

DEFINE_METHOD_CHECKER(int, Method, (bool) const);
DEFINE_METHOD_CHECKER(int*, Test, (int&, char) volatile);

Т.е. Вы просто указываете полную сигнатуру метода + возвращаемый тип. Удобно в том плане, что различие между этим и действительным объявлением метода в классе — только 2 запятые.

Кстати, я пошёл дальше и ради интереса — а можно ли узнать о методе, если он шаблонный?
#define DEFINE_TEMPLATE_METHOD_CHECKER(RETURN_TYPE, METHOD_NAME, PARAMETERS_INST, ARGS) \
template<typename T>                                                    \
struct Is ## METHOD_NAME ## TemplateMemberFunctionExists				\
{                                                                       \
private:                                                                \
	typedef char True;                                                  \
	typedef char (&False)[2];                                           \
	template<typename U, RETURN_TYPE (U::*)PARAMETERS_INST = &U::template METHOD_NAME ARGS >\
	struct Checker														\
	{                                                                   \
		typedef True Type;												\
	};                                                                  \
	template<typename U>                                                \
	static typename Checker<U>::Type Tester(const U*);                  \
	static False Tester(...);                                           \
public:                                                                 \
	enum { value = (sizeof(Tester(static_cast<const T*>(0))) == sizeof(True)) }; \
}

// IsVCFailTemplateMemberFunctionExists<T>::value
DEFINE_TEMPLATE_METHOD_CHECKER(void, VCFail, (), <int>);

// IsVCOkTemplateMemberFunctionExists<T>::value
DEFINE_TEMPLATE_METHOD_CHECKER(void, VCOk, (int, bool), <int>);

#include <iostream>

class Exists
{
public:
	template<typename T>
	void VCFail();

	template<typename T>
	void VCOk(T, bool);

};

class NotExists
{
};

int main()
{
	std::cout << IsVCOkTemplateMemberFunctionExists<Exists>::value << std::endl;
	std::cout << IsVCOkTemplateMemberFunctionExists<NotExists>::value << std::endl;

	//std::cout << IsVCFailTemplateMemberFunctionExists<Exists>::value << std::endl;
	std::cout << IsVCFailTemplateMemberFunctionExists<NotExists>::value << std::endl;
}

И, всё работает, только не со студией:) 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. Может, это смешно, но всё таки спрошу — почему не сделать что-то типа такого макроса для проверки есть ли метод в классе ?:
#define DEFINE_METHOD_CHECKER(RETURN_TYPE, METHOD_NAME, PARAMETERS)     \
template<typename T>                                                    \
struct Is ## METHOD_NAME ## MemberFunctionExists                        \
{                                                                       \
private:                                                                \
    typedef char True;                                                  \
    typedef char (&False)[2];                                           \
    template<typename U, RETURN_TYPE (U::*)PARAMETERS = &U::METHOD_NAME>\
    struct Checker                                                      \
    {                                                                   \
        typedef True Type;                                              \
    };                                                                  \
    template<typename U>                                                \
    static typename Checker<U>::Type Tester(const U*);                  \
    static False Tester(...);                                           \
public:                                                                 \
    enum { value = (sizeof(Tester(static_cast<const T*>(0))) == sizeof(True)) }; \
}

// IsMethodMemberFunctionExists<T>::value
DEFINE_METHOD_CHECKER(int, Method, (bool));
// IsTestMemberFunctionExists<T>::value
DEFINE_METHOD_CHECKER(int*, Test, (int&, char));

#include <iostream>

class Exists
{
public:
    int Method(bool);
    int* Test(int&, char);
    
};

class NotExists
{
};

int main()
{
    std::cout << IsMethodMemberFunctionExists<Exists>::value << std::endl;
    std::cout << IsTestMemberFunctionExists<Exists>::value << std::endl;

    std::cout << IsMethodMemberFunctionExists<NotExists>::value << std::endl;
    std::cout << IsTestMemberFunctionExists<NotExists>::value << std::endl;
}
Попроще, чем у 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;
	}
};


Используем:
typedef TypeList<double, float, float, double, int, char, char, int, char> TL;
ForEach<Call, TL>()();


Результат:
double
Call<float>
Call<float>
double
int
char
char
int
char
Да, конечно. Ответ: just for fun. Тут всё можно заменить на что-то вроде:
template<typename T, typename ...Args>
struct Exists :
    std::false_type
{
};

template<typename T, typename ...Args>
struct Exists<T, T, Args...> :
    std::true_type
{
};

template<typename T, typename NotT, typename ...Args>
struct Exists<T, NotT, Args...> :
    std::integral_constant<bool, Exists<T, Args...>::value>
{
};

и т.д.
Спасибо за пример
Извините, но я немножко не понял концепцию. Обычно, ведь, каждый параметр шаблона, в таких случаях, отвечает за некоторое свойство(которое имеет ряд значений). Например, 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.
Спасибо. Вы имеете в виду случай, когда начинается полный ад? — что-то такое:)
Если честно, не понял по поводу slice:
Компилятор сделает срез базового типа по отнаследованному. И если указатель увеличился с 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;
}


Вывод:
test: @a is not B: Bad dynamic_cast!
10 30
Кому интересно — раздел 15.4 «Ограничения на аргументы шаблонов»
Об этом(как-то «ограничения на типы» или что-то в этом роде), кстати, Страуструп писал в «Дизайн и эволюция C++». И это в 90тые годы — не помню, какие доводы были за и против.

Information

Rating
Does not participate
Location
Киев, Киевская обл., Украина
Registered
Activity