Это действительно единственный способ получить корректный адрес для функции экземпляра:
typedef CBitmap * (CDC::* SelectObjectBitmap)(CBitmap*);
SelectObjectBitmap pmf = (SelectObjectBitmap)&CDC::SelectObject;
Во-первых, нужно создать определение типа, и затем нужно использовать это, чтобы вынудить компилятор выбрать корректный перегруженный метод при взятии его адреса?
Нет ли никакой синтаксис, который является более естественным, и автономным, таким как:
SelecdtObjectBitmap pmf = &CDC::SelectObject(CBitmap*);
Я часто использую ScopeGuard в моем коде. И одно очевидное использование должно гарантировать, что любые временные объекты CDC сначала выбраны в данный DC, затем удалили в выходе объема, заставив мой код протечь свободный даже при исключительных обстоятельствах - и одновременно очистив записанный код (глупый несколько путей выхода и попытки/выгоды и так далее, чтобы попытаться обработать удаление любых выбранных объектов от данного CDC).
Таким образом, более полный пример того, что я в настоящее время вынуждаюсь сделать, похож:
// get our client rect
CRect rcClient;
GetClientRect(rcClient);
// get the real DC we're drawing on
PAINTSTRUCT ps;
CDC * pDrawContext = BeginPaint(&ps);
// create a drawing buffer
CBitmap canvas;
canvas.CreateCompatibleBitmap(pDrawContext, rcClient.Width(), rcClient.Height());
CDC memdc;
memdc.CreateCompatibleDC(pDrawContext);
//*** HERE'S THE LINE THAT REALLY USES THE TYPEDEF WHICH i WISH TO ELIMINATE ***//
ScopeGuard guard_canvas = MakeObjGuard(memdc, (SelectObjectBitmap)&CDC::SelectObject, memdc.SelectObject(&canvas));
// copy the image to screen
pDrawContext->BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memdc, rcClient.left, rcClient.top, SRCCOPY);
// display updated
EndPaint(&ps);
Это всегда казалось мне глупо адом, что мне нужна к определению типа каждая перегруженная функция, из которой я хочу взять адрес.
Так... существует ли лучший путь?!
Править: На основе ответов люди предоставили, я полагаю, что у меня есть решение моей базовой потребности: т.е. иметь более естественный синтаксис для MakeGuard, который выводит корректное переопределение SelectObject для меня:
template
ObjScopeGuardImpl1 MakeSelectObjectGuard(CDC & dc, GDIObj * pGDIObj)
{
return ObjScopeGuardImpl1::MakeObjGuard(dc, (GDIObj*(CDC::*)(GDIObj*))&CDC::SelectObject, dc.SelectObject(pGDIObj));
}
Который заставляет мой выше кода измениться на:
ScopeGuard guard_canvas = MakeSelectObjectGuard(memdc, &canvas);
//////////////////////////////////////////////////////////
Для тех, кто мог бы здесь искать версию не-MFC того же самого:
//////////////////////////////////////////////////////////////////////////
//
// AutoSelectGDIObject
// selects a given HGDIOBJ into a given HDC,
// and automatically reverses the operation at scope exit
//
// AKA:
// "Tired of tripping over the same stupid code year after year"
//
// Example 1:
// CFont f;
// f.CreateIndirect(&lf);
// AutoSelectGDIObject select_font(*pDC, f);
//
// Example 2:
// HFONT hf = ::CreateFontIndirect(&lf);
// AutoSelectGDIObject select_font(hdc, hf);
//
// NOTE:
// Do NOT use this with an HREGION. Those don't need to be swapped with what's in the DC.
//////////////////////////////////////////////////////////////////////////
class AutoSelectGDIObject
{
public:
AutoSelectGDIObject(HDC hdc, HGDIOBJ gdiobj)
: m_hdc(hdc)
, m_gdiobj(gdiobj)
, m_oldobj(::SelectObject(m_hdc, gdiobj))
{
ASSERT(m_oldobj != m_gdiobj);
}
~AutoSelectGDIObject()
{
VERIFY(m_gdiobj == ::SelectObject(m_hdc, m_oldobj));
}
private:
const HDC m_hdc;
const HGDIOBJ m_gdiobj;
const HGDIOBJ m_oldobj;
};
//////////////////////////////////////////////////////////
Спасибо Все, кто ответил и прокомментировал!:D
То, что вы спрашиваете, похоже на более ранний вопрос, и ответ, который я дал здесь, имеет отношение к нему.
из раздела 13.4 / 1 («Адрес перегруженной функции» («Over.Over]):
Использование перегруженного имени функции без аргументов решается В определенных контекстах к функции указатель на функцию или указатель на функцию элементов для определенной функции из набора перегрузки. Имя шаблона функции считается называть набор перегруженных функций в таких контекстах. Выбранная функция заключается в том, что тип которого соответствует типу цели, необходимый в контексте. Цель может быть
- объектом или ссылкой инициализирована (8,5, 8.5.3),
- левая сторона назначения (5.17),
- параметр функции (5.2.2),
- Параметр определенного пользовательского оператора (13.5),
- возвращаемого значения функции, функции оператора или преобразования (6.6.3) или
- явного преобразования типа (5.2.3, 5.2.9 , 5.4).
Название функции перегрузки может предшествовать оператору
&
. Перегруженное имя функции не должно использоваться без аргументов в контекстах, отличных от перечисленных. [ Примечание: Любой резервный набор скобок, окружающих перегруженное имя функции, игнорируется (5.1). ]
В вашем случае целевая цель из вышеуказанного списка - это третий, параметр вашего makeobjguard
функция. Однако я подозреваю, что это шаблон функции, и один из параметров типа для шаблона - это тип указателя функции. Компилятор имеет улов-22. Он не может вывести тип параметра шаблона, не зная, какая перегрузка выбрана, и она не может автоматически выбирать, какую перегрузку вы имеете в виду, не зная типа параметра.
Следовательно, вы должны помочь этому. Вы можете либо набрать указатель метода, как вы делаете сейчас, или вы можете явно указать тип аргумента шаблона, когда вы вызываете функцию: makeobjguard
. В любом случае, вам нужно знать тип. Вы не должны строго иметь имя TYPEDEF для типа функции, но это, безусловно, помогает читабельность.
Вы можете избежать использования Typedef, но это действительно не красиво:
void foo(int){
std::cout << "int" << std::endl;
}
void foo(float){
std::cout << "float" << std::endl;
}
int main()
{
typedef void (*ffp)(float);
ffp fp = (void (*)(float)) foo; // cast to a function pointer without a typedef
((ffp)fp)(0);
}
лучше придерживаться Typedef.
Вы, кажется, неправильно понимаете корня проблемы. До тех пор, пока бетонный тип на приемной стороне присвоения / инициализации, известен для компилятора, вы не должны иметь никаких усилий для «выбрать» вообще, если ваш Typedef определяется как
typedef CBitmap * (CDC::* SelectObjectBitmap)(CBitmap*);
, а затем инициализация
SelectObjectBitmap pmf = &CDC::SelectObject;
Требуется, чтобы вызвать разрешение перегрузки и выбирать правильную перегруженную версию функции без необходимости явного отряда. Это на самом деле только одно место в C ++ при разрешении перегрузки в правой части выражения / инициализации зависит от левой стороны.
Конечно, то же самое должно работать без типов.
Хорошо, увидев, что то, что вы на самом деле делаете, передает адрес метода к функции шаблона в качестве зависимого типа аргумента: конечно, в этом случае у вас есть либо 1), выберите правильную перегрузку с помощью активов, или 2) исправить тип параметра функции, явно указывая аргумент шаблона.
Конечно, вы можете просто предварительно выбрать правильную перегрузку, выполняя
SelectObjectBitmap pmf = &CDC::SelectObject;
, а затем пройдите PMF
к функции шаблона.
Короткий ответ - «нет», невозможно избежать создания кадра данных. ggplot
требует, чтобы данные находились в кадре данных. При использовании qplot
можно присвоить ему отдельные векторы для x и y, но внутри него по-прежнему создается кадр данных из передаваемых параметров.
Я согласен с предложением Джубы - научись использовать функцию изменения формы
или лучше, чем изменение формы
с функциями плавления
/ литья
. После быстрого размещения данных в длинном формате создание удивительных графиков ggplot
становится на шаг ближе!
Это далеко не обычная практика, на самом деле это, вероятно, будет рассматриваться как плохая практика!
CSS используется для установки стилей страницы и визуализируется при загрузке страницы. Javascript вступает в игру после загрузки страницы и может манипулировать существующими стилями и страницей.
Если бы вы внедрили его во все JS, это было бы крайне неэффективно! DOM манипуляции становится дорогим, если вы делаете это много в JS, и делать все стили в javascript вместо CSS будет много манипуляции. Нагрузка на клиента была бы нелепой и наверняка было бы заметное отставание в клиенте, так как он пытался внести все эти изменения. Кроме того, что произойдет, если клиент отключил javascript? Там идет весь ваш сайт внешний вид и ощущение.
Подумайте о CSS как об определении того, как страница выглядит и должна быть визуализирована, а затем подумайте о JS как об изменении этой страницы после завершения рендеринга. Вы не должны вставлять что-либо в javascript, что вы можете сделать с простым CSS стиль спереди.
-121--4132739-Вам не нужно использовать typedef. Вы просто используете typedef для создания имени типа, затем используйте этот тип для определения указателя, и в typecast для инициализации указателя. Если вы действительно хотите, вы можете использовать тип непосредственно для обоих, но в конечном итоге вы повторяете один и тот же (часто длинный) тип как для определения, так и для типа. Для несколько упрощенного, отдельного примера:
struct XXX {
int member() { return 0; }
int member(int) { return 1; }
};
int main() {
int (XXX::*pmfv)(void) = (int (XXX::*)())&XXX::member;
int (XXX::*pmfi)(int) = (int (XXX::*)(int))&XXX::member;
return 0;
}
Хотя это возможно и должно быть принято любым надлежащим образом функционирующим компилятором, я не могу сказать, что я бы действительно посоветовал это - в то время как он создает и инициализирует указатель в одной инструкции, если задействованный тип имеет длинное имя, он, вероятно, в конечном итоге будет представлять собой пару строк кода, как раз из-за длины.
Я полагаю, что C++ 0x, auto
должны позволить первый пример выше быть сокращены до чего-то подобного:
auto pmf = (int (XXX::*)())&XXX::member;
Это должно сделать гораздо проще, чтобы избежать typedef (и в зависимости от компилятора вы используете, вы можете уже иметь это доступно).