- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
#include <iostream>
using namespace std;
struct NG
{
template<class T>
struct get
{
typedef typename T::f type;
};
};
template <typename T, typename NameGetter>
struct has_member_impl
{
typedef char matched_return_type;
typedef long unmatched_return_type;
template <typename C>
static matched_return_type f(typename NameGetter::template get<C>*);
template <typename C>
static unmatched_return_type f(...);
public:
static const bool value = (sizeof(f<T>(0)) == sizeof(matched_return_type));
};
template <typename T, typename NameGetter>
struct has_member{
enum { value = has_member_impl<T, NameGetter>::value };
};
class T{};
int main() {
cout<<has_member<T, NG>::value;
return 0;
}
has_member - чужой велосипед, а примера записи NameGetter в статье не указано.
http://www.gockelhut.com/c++/articles/has_member
Не смотрите ниже, если хотите поломать ещё мозги над задачей:
Вот если бы это как-то прикрутить для виртуальных функций, чтобы проверять их конкретизацию в дочерних классах... Я знаю про override (везёт же некоторым), но от этого не легче.
А вот ниже озвученный вариант с читабельным ассертом мне нраица. В таком контексте код даже и не говно, а весьма полезная няшка.
Пойду читать ссылку.
Ну и в любом случае не работает с шаблонными методами. А с перегружеными работает не так приятно.
Нет, не кастится. void* минимум вдвое меньше указателя на член.
Это я в более простых типах продемонстрировал проблему. Указатель на метод гораздо сложнее указателя на функцию.
Идея в том, что указатель на существующий член reinterpret_cast'ом с горем пополам кастуется в void *, а указатель на несуществующий член - нет. Для проверки существования этого достаточно. Юзать результат каста никто не будет...
Можно попробовать сделать ещё шаблонной шаблонной, чтобы с шаблонными методами заработало.)))
Вот только для этого и нужен каст в void ;) Чтобы проверять имя, не обращая внимания на сигнатуру... Ну если я сегодня не туплю...
> Чтобы что-то скастовать, это что-то надо получить
Ну вроде как в примере LispGovno оно не окончательно ломается на &test::foo, а просто выбирает другую версию функции f... Скорее всего и с (void*)&test::foo прокатит.
Килограммы шаблонных выкрутасов там, где достаточно обычной перегрузки для базового класса иерархии. Возможно, нескольких перегрузок для разных деревьев. Но, при правильной иерархии, скорее всего у них один предок с печатающим интерфейсом.
И говно разруливается кодом вида:
Но шаблонные извращения мне нравятся. Возьму на заметку.)
> virtual
Ты в скорости исполнения потерял. Они обменивают понятность и скорость компиляции на скорость исполнения.
И одиночные вызовы из конкретного объекта (когда тип известен при компиляции) оптимизирующий компилятор вполне может заинлайнить при его желании.
В теории это можно применять для оптимизации обобщённых алгоритмов с graceful degradation (если у класса есть "быстрый" метод - используем его, если нет - юзаем обходной медленный путь) или вывода более внятных сообщений в статик-ассёртах.
> грязные
Сам то на лиспе, хаскеле и скале пишешь. Ктобы говорил про грязные хаки и извращения. От извращенца слышу.
> функцианально чисты
Мечтай больше: unsafePerformIO
Ты просто не понял дзен. unsafePerformIO - это чистилище чистых сишных душ функций.
Я всегда своим говорю, что так делать нельзя и вспоминаю историю бывшего сотрудника:
http://govnokod.ru/8025
Он сейчас свою сборку mingw пишет и в маиллисты буста похаживает. А вот работает ли где - не уверен.
http://www.cyberforum.ru/post5379548.html