int main()
{
bool b1 = fff(1, ID); // Компилируется
ignore_result(fff(2, ID)); // Компилируетсяif (fff(2, ID)); // Компилируется
fff(1, ID); // НЕ Компилируется! error C2027: use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'
}
К сожалению параметр RESULT_CHECK_PARAM — необходимость — сейчас будет видно. Собственно исходный код:
// Стратегии сообщения об ошибке (куда сейчас без стратегий? :) )
// На выбор - ошибка компиляции, варнинг, ошибка без использования boost (специально для нелюбителей boost'а :) )struct error_report_policy
{
template<typename> static void report()
{
BOOST_STATIC_ASSERT(false);
}
};
struct error_report_no_boost_policy
{
template<typename> static void report()
{
typedef char error[-1];
}
};
struct warning_report_policy
{
template<typename> static void report()
{
BOOST_STATIC_WARNING(false);
}
};
namespace
{
// Вспомогательный класс - ниже будет видно зачемtemplate<int id>
struct result_check_helper
{
static void fake() {}
};
}
// Собственно класс для возвращаемого значения
// id - вспомогательный параметр
// type - тип возвращаемого значения - bool, int, HRESULT и т.д.
// report_policy - одна из вышеприведённых стратегий информирования об ошибкеtemplate<int id, typename type = bool, typename report_policy = error_report_policy>
class checked_result
{
public:
checked_result(type value)
: value_(value)
{}
operator type ()
{
// Обращаемся к классу result_check_helper<id>
// ниже будет видно зачем
result_check_helper<id>::fake();
return value_;
}
~checked_result()
{
// ЗДЕСЬ!
// Определяем есть ли класс result_check_helper<id>,
// что фактически равнозначно тому, вызывается operator type () или нет!
__if_not_exists (result_check_helper<id>)
{
report_policy::report<void>();
}
}
private:
type value_;
};
// Вспомогательный класс для передачи уникальных идентификаторов вызоваtemplate<int id> struct long_and_inconvenient_name {static const int id = id;};
// Вспомотельный макрос для генерации уникальных идентификаторов вызова
// В реальности надо какое-то более длинное имя, чем ID, но здесь для простоты так#define ID long_and_inconvenient_name<__COUNTER__>()
// Вспомогательный макрос#define RESULT_CHECK_PARAM long_and_inconvenient_name<id>
// Функции для явного игнорирования возвращаемого значенияinline void ignore_result(bool) {}
inline void ignore_result(int) {}
//...
Здравствуйте, _Obelisk_, Вы писали:
_O_>Здравствуйте, remark, Вы писали:
R>>
Свершилось! Форсирование проверки возвращаемого значения в компайл-тайм возможно!
R>>В начале несколько вводных слов, что б было понятно о чём речь:
_O_>Супер! Только вопрос — зачем? _O_>Если программист хочет игнорировать возвращаемое значение — пущай игнорирует.
Я думаю, это одна из тех вещей, которые не объяснить. Те, кто поняли зачем, тем понятно, а те кто не поняли, тем не объяснить.
Ну это типа как "А зачем программировать на С++, когда есть С?" или "Зачем использовать исключения, когда есть коды возврата?"
Здравствуйте, IROV.., Вы писали:
IRO>Здравствуйте, remark, Вы писали:
IRO>...
IRO>
IRO>fff(1, ID /* - фээ некрасиво */ );
IRO>
IRO>
Согласен.
Но во-первых, надо с чего-то начинать. Это первый рабочий вариант, который я видел (который работает и для методов). На rsdn точно ничего аналогичного нет, в других местах тоже не видел. В Overload ещё не так давно кто-то писал про вариант типа здесь
Здравствуйте, johny5, Вы писали:
J>Ну во первых нужно было прям перед заголовком вот так написать: J>Microsoft specific J>Я может дальше и читать бы не стал
Читай внимательнее:
В gcc для этих целей есть __attribute__((warn_unused_result)). Но что делать пользователям msvc?
J>Тут наверно таки вызов fff_wrap?
Да, конечно, описался...
J>Я так понимаю, при каждом вызове такой функции, будет инстанцироваться result_check_helper<int id>::fake() J>У линкера башню то не порвёт? J>
Нет. Тем более, что символ с внутренним связыванием.
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, remark, Вы писали:
R>>
Свершилось! Форсирование проверки возвращаемого значения в компайл-тайм возможно!
R>>В начале несколько вводных слов, что б было понятно о чём речь:
R>>Работает на msvc71/80. В рантайм оверхед нулевой.
R>>
NB>может стоит ID сделать первым параментром, на случай если у функции есть параметры по умолчанию?
Это можно варьировать по желанию для каждой функции.
В данном случае просто хотелось более показать сходство с оригинальной функцией.
NB>PS: а что, действительно большая проблема в проверкой?
Как вы думайте сколько реализаций функции fff_wrap в бинарнике ?
Вряд ли такое поведение функции ожидается, а отказ от статических переменных в функции ИМХО слишком суров.
Re[4]: [Trick] Форсирование проверки возвращаемого значения
Здравствуйте, Antipov, Вы писали:
A>Как вы думайте сколько реализаций функции fff_wrap в бинарнике ? A>Вряд ли такое поведение функции ожидается, а отказ от статических переменных в функции ИМХО слишком суров.
R>Я думаю, это одна из тех вещей, которые не объяснить. Те, кто поняли зачем, тем понятно, а те кто не поняли, тем не объяснить. R>Ну это типа как "А зачем программировать на С++, когда есть С?" или "Зачем использовать исключения, когда есть коды возврата?"
На эти два вопросы имеются ответы, а вот необходимости в compile-time проверки учета возвращаемого значения не вижу.
Душа обязана трудиться! (с) Н.Заболоцкий.
Re[4]: [Trick] Форсирование проверки возвращаемого значения
Здравствуйте, _Obelisk_, Вы писали:
_O_>Здравствуйте, remark, Вы писали:
R>>Я думаю, это одна из тех вещей, которые не объяснить. Те, кто поняли зачем, тем понятно, а те кто не поняли, тем не объяснить. R>>Ну это типа как "А зачем программировать на С++, когда есть С?" или "Зачем использовать исключения, когда есть коды возврата?"
_O_>На эти два вопросы имеются ответы, а вот необходимости в compile-time проверки учета возвращаемого значения не вижу.
Без форсирования:
1. Неправильный код написать легче, чем правильный
2. Не явны намерения программиста: он забыл проверить или хотел это сделать?
3. Код менее читабельный: f() — а эта функция что-то ещё и возвращает?
Прикольно, но ИМХО неудобства написания шаблонного враппера к каждому нешаблонному методу здесь слишком большие. И это не удовлетворяет более ранним требования — "есть дофига старого кода, хочу проверить ошибки там" — нужен параметр ID.
Можно конечно макросы ещё написать — #define Foo(x) Foo(x, ID), но это всё более и более уход в Темную Сторону.
или code guide с написанием скрипта — "эту функцию можно вызывать только так — ^bool :i = foo\(.*\);$ и как if \(.*foo" (это не реальные регэкспы а просто как начинать их писать)
Можно даже скрипт не писать, а сразу Edit->Find In Files. И заграть в макрокнопку студии.
Правильно работающая программа — просто частный случай Undefined Behavior
Re: [Trick] Форсирование проверки возвращаемого значения
"IROV.." <35375@users.rsdn.ru> wrote in message news:2279806@news.rsdn.ru... > Здравствуйте, remark, Вы писали: > > R>
Свершилось! Форсирование проверки возвращаемого значения в компайл-тайм возможно!
> > как по мне на лицо борьба с ветряными мельницами! а именно, ну а кто мне _леньтяю_ запретит писать вот такое.. > >
> if( foo( 1, 2 ) );
>
> >
Так в этом то и состоит цель этой затеи, чтоб заставить пользователя так писать. Таким образом пользователь как бы говорит: "я осознанно проигнорировал результат, всю ответственность беру на себя...".
Цель, вообще говоря, хорошая, но, имхо, не такой ценой как в предлагаемом варианте: один только макрос RESULT_CHECK_PARAM чего стоит.
Posted via RSDN NNTP Server 2.0
--
Не можешь достичь желаемого — пожелай достигнутого.