Почему C++ не имеет указателя на тип функции членства?

Я понял это с помощью оригинальных кодеров, от которых я его купил, это ошибка синтаксиса. Я использовал одинарные и двойные кавычки. Используйте одно или другое, но не оба;) Я только что видел, что это плохо,

Все типы номеров хранятся в таблице pm_room, но в этой таблице есть столбец идентификатора отеля, чтобы указать, для какого отеля тип номера для правильного кода

$result_room = $db->query("SELECT * FROM pm_room WHERE checked = 1 AND id_hotel = ".$hotel_id." AND lang = ".LANG_ID);
11
задан Rocketmagnet 20 January 2009 в 17:24
поделиться

9 ответов

@RocketMagnet - Это в ответ на Ваш другой вопрос, тот, который был маркирован дубликат. Я отвечаю на тот вопрос, не этого.

В целом указатель C++ на функции членства не может портативно быть брошен через иерархию классов. Это сказало, что можно часто выходить сухим из воды. Например:

#include <iostream>
using std::cout;
class A { public: int x; };
class B { public: int y; };
class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};

int main() {
    typedef void (A::*pmf_t)();
    C c; c.x = 42; c.y = -1;

    pmf_t mf = static_cast<pmf_t>(&C::foo);
    (c.*mf)();
}

Скомпилируйте этот код, и компилятор справедливо жалуется:

$ cl /EHsc /Zi /nologo pmf.cpp
pmf.cpp
pmf.cpp(15) : warning C4407: cast between different pointer to member representations, compiler may generate incorrect code

$

Таким образом для ответа, "почему C++ не имеет pointer-to-member-function-on-void-class?" тот этот мнимый base-class-of-everything, не имеет никаких участников, таким образом, нет никакого значения, которое Вы могли безопасно присвоить ему! "пусто (C::) ()" и "пусто (void::) ()" взаимно несовместимые типы.

Теперь, я держал пари, что Вы думаете, "ожидают, у меня есть указатели функции актера очень хорошо прежде!" Да, Вы можете иметь, с помощью reinterpret_cast и единичное наследование. Это находится в той же категории другого давать иное толкование броскам:

#include <iostream>
using std::cout;
class A { public: int x; };
class B { public: int y; };
class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};
class D { public: int z; };

int main() {
    C c; c.x = 42; c.y = -1;

    // this will print -1
    D& d = reinterpret_cast<D&>(c);
    cout << "d.z == " << d.z << "\n";
}

Итак, если void (void::*)() действительно существовал, но нет ничего, что Вы могли безопасно/портативно присвоить ему.

Традиционно, Вы используете функции подписи void (*)(void*) где угодно Вы были бы вещь использования void (void::*)(), потому что, в то время как членские указатели функции не бросают хорошо вверх и вниз по иерархии наследования, пустые указатели действительно бросают хорошо. Вместо этого:

#include <iostream>
using std::cout;
class A { public: int x; };
class B { public: int y; };
class C : public B, public A { public: void foo(){ cout << "a.x == " << x << "\n";}};

void do_foo(void* ptrToC){
    C* c = static_cast<C*>(ptrToC);
    c->foo();
}

int main() {
    typedef void (*pf_t)(void*);
    C c; c.x = 42; c.y = -1;

    pf_t f = do_foo;
    f(&c);
}

Таким образом к Вашему вопросу. Почему C++ не поддерживает этот вид кастинга. Типы Pointer-to-member-function уже должны иметь дело с виртуальным по сравнению с невиртуальными базовыми классами, и виртуальный по сравнению с невиртуальными функциями членства, всеми в том же типе, расширяя их к 4*sizeof (пусто*) на некоторых платформах. Я думаю, потому что это далее усложнило бы реализацию pointer-to-member-function, и необработанные указатели функции уже решают эту проблему так хорошо.

Как другие прокомментировали, C++ дает устройствам записи библиотеки достаточно инструментов, чтобы сделать это, и затем 'нормальные' программисты как Вы и я должны пользоваться теми библиотеками вместо того, чтобы потеть эти детали.

Править: отмеченная общественная Wiki. Только редактирование, чтобы включать соответствующие ссылки на стандарт C++ и добавить в курсиве. (особенно добавьте ссылки на стандарт, где мое понимание было неправильным! ^_^)

17
ответ дан 3 December 2019 в 01:34
поделиться

Как другие указали, C++ действительно имеет тип указателя функции членства.

Термин, который Вы искали, "связывается функция". Причина, которую C++ не обеспечивает сахару синтаксиса для функциональной привязки, из-за ее философии только обеспечения самых основных инструментов, с которыми можно затем создать все, что Вы хотите. Это помогает сохранить язык "маленьким" (или по крайней мере, меньше ума bogglingly огромный).

Точно так же C++ не имеет блокировки {} примитивной как C#, но это имеет RAII, который используется scoped_lock повышения.

Существует, конечно, философская школа, которая говорит, что необходимо добавить сахар синтаксиса для всего, что могло бы быть полезным. Что бы там ни было C++ не принадлежит той школе.

12
ответ дан 3 December 2019 в 01:34
поделиться

Я думаю, что Вы ищете, мог бы быть в этих библиотеках...

Быстрые делегаты http://www.codeproject.com/KB/cpp/FastDelegate.aspx

Повышение. Функциональный http://www.boost.org/doc/libs/1_37_0/doc/html/function.html

И вот является очень полное объяснение связанных с указателем функции вопросов http://www.parashift.com/c++-faq-lite/pointers-to-members.html

4
ответ дан 3 December 2019 в 01:34
поделиться

Это делает.

Например,

int (Fred::*)(char,float)

указатель на функцию членства класса Fred это возвращается int и берет a char и a float.

3
ответ дан 3 December 2019 в 01:34
поделиться

Я думаю, что ответ - то, что разработчики C++ принимают решение не иметь на языке вещи, которые могли быть столь же легко реализованы в библиотеке. Ваше собственное описание того, что Вы хотите, дает совершенно разумный способ реализовать его.

Я знаю, что это звучит забавным, но C++ является минималистическим языком. Они действительно оставляли библиотекам все, что они могли оставить им.

2
ответ дан 3 December 2019 в 01:34
поделиться

TR1 имеет станд.:: tr1:: функция, и это будет добавлено к C++ 0x. Так в некотором смысле это действительно имеет его.

Одни из принципов проектирования C++: Вы не платите за то, что Вы не используете. Проблема с делегатами стиля C#, они тяжелы и требуют поддержки языка, которую все оплатили бы то, использовали ли они их или нет. Именно поэтому реализация библиотеки предпочтена.

Причина делегаты тяжелы, состоит в том, что указатель метода часто больше, чем нормальный указатель. Это происходит каждый раз, когда метод является виртуальным. Указатель метода вызовет другую функцию в зависимости от того, какой базовый класс использует его. Это требует по крайней мере двух указателей, vtable и смещения. Существует другая странность, связанная с методом, от класса, вовлеченного во множественное наследование.

Однако я не разработчик компилятора. Возможно, было возможно сделать новый тип для указателей связанного метода, которые ниспровергали бы виртуальность метода, на который ссылаются (в конце концов, мы знаем то, что - базовый класс то, если метод связывается).

1
ответ дан 3 December 2019 в 01:34
поделиться

Проблемой являются, конечно, не основы наличия объектного указателя и указателя функции в одном простом в использовании пакете, потому что Вы могли сделать это использование указателя и преобразователя. (Такие преобразователи уже используются VC ++ на x86 для поддержки указателей на виртуальные функции членства, так, чтобы эти указатели только подняли 4 байта.) Вы могли бы закончить с большим количеством преобразователей, это верно, но люди уже полагаются на компоновщика для устранения дублирующихся шаблонных инстанцирований - я делаю, так или иначе - и существуют только так многие vtable, и это смещает, Вы закончите с на практике. Издержки, вероятно, не были бы значительными ни для какой обоснованно измеренной программы, и если Вы не будете использовать этот материал затем, то это ничего не будет стоить Вам.

(Архитектура, которая традиционно использует TOC, сохранила бы указатель TOC в части указателя функции, а не в преобразователе, как они уже должны будут сделать.)

(Этот новый тип объекта не был бы точно substitutable для нормального указателя на функцию, конечно, потому что размер будет отличаться. Они были бы, однако, записаны то же в извещателе.)

Проблемой, которую я вижу, является проблема соглашения о вызовах: поддержка указателей на функции, этот путь мог бы быть хитрым в общем случае, потому что сгенерированный код должен будет подготовить аргументы (включенный) тот же путь без учета к фактическому типу вещи, функциональной или функции членства, на которую указывает указатель.

Это - вероятно, не грандиозное предприятие на x86, по крайней мере, не с thiscall, потому что Вы могли просто загрузить ECX независимо и признать, что, если для функции вызова не нужен он затем, это будет поддельным. (И я думаю, что VC ++ предполагает, что ECX является поддельным в этом случае так или иначе.), Но на архитектуре, которая передает аргументы в пользу именованных параметров в регистрах к функциям, можно закончить с изрядным количеством перестановки в преобразователе, и если аргументы стека продвинуты слева направо затем, Вы в основном наполнены. И это не может быть согласовано статически, потому что в пределе нет никакой информации о перекрестной единице перевода.

[Редактирование: MSalters, в комментарии к сообщению rocketmagnet выше, указывает что, если обе объектных функции И известны, то это смещение и так далее может быть сразу определено. Это полностью не произошло со мной! Но, с этим в памяти, я предполагаю там потребность только быть сохраненным точный объектный указатель, возможно, сместите, и точный указатель функции. Это делает преобразователей совершенно не нужными - я думаю - но я вполне уверен, которым одинаково остались бы проблемы того, чтобы указывать на функции членства и не являющиеся членом функции.]

1
ответ дан 3 December 2019 в 01:34
поделиться

C++ уже является большим языком, и добавляющий, что это сделало бы его больше. То, что Вы действительно хотите, еще хуже, чем просто связанная функция членства, это - что-то ближе для повышения:: функция. Вы хотите сохранить обоих a void(*)() и пара для обратных вызовов. В конце концов, причина состоит в том, что Вы хотите давание вызывающей стороне полного обратного вызова, и вызываемый не должен заботиться о точных деталях.

Размер, вероятно, был бы sizeof(void*)+sizeof(void(*)()). Указатели на функции членства могут быть больше, но это вызвано тем, что они развязаны. Они должны иметь дело с возможностью что youre' взятие адреса виртуальной функции, например. Однако встроенный тип bound-pointer-to-member-function не пострадал бы от этих издержек. Это может разрешить точную функцию, которую назовут во время привязки.

Это не возможно с повышением UDT.:: функция не может отбросить издержки PTMF, когда это связывает объектный указатель. Необходимо знать, понимают структуру PTMF, vtable, и так далее - весь нестандартный материал. Однако мы могли бы добраться там теперь с C++ 1x. После того как это находится в станд.:: это - справедливая игра для поставщиков компилятора. Сама стандартная реализация библиотеки не является портативной (см., например, type_info).

Вы все еще хотели бы иметь некоторый хороший синтаксис, я предполагаю, даже если поставщик компилятора реализует это в библиотеке. Я хотел бы std::function<void(*)()> foo = &myX && X::bar. (Это не сталкивается с существующим синтаксисом, как X:: панель не является выражением - только &X:: панель),

0
ответ дан 3 December 2019 в 01:34
поделиться

Мне приходит в голову, что методы имеют неявное this аргумент, таким образом, a c указатель на метод недостаточен, чтобы позволить методу быть названным (потому что нет никакого способа определить, для которого должен использоваться экземпляр this (или даже если какой-либо экземпляр является в настоящее время существующим)).

Править: Rocketmagnet комментирует, что он обратился к этому в вопросе, и это, кажется, имеет место, хотя я думаю, что это было добавлено после того, как я запустил этот ответ. но я скажу "мою вину", так или иначе.

Поэтому позвольте мне подробно останавливаться на мысли немного.

C++ тесно связан с c и имеет все свои внутренние типы, совместимые с более ранним языком (в основном из-за истории c++ разработка, я предполагаю). Так, внутреннее c++ указатель является a c указатель, и неспособен к поддержке использования, которое Вы просите.

Конечно, Вы могли создать производный тип, чтобы сделать задание---как во внедрении BOOST---, но такое существо входит в состав библиотеки.

-1
ответ дан 3 December 2019 в 01:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: