Created
February 20, 2018 10:08
-
-
Save anatoly-spb/7afed6e575e024905b11e53111a26b0d to your computer and use it in GitHub Desktop.
Tagging
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////////////////////////////////////////////////////////////////////// | |
// params.h | |
// | |
// Файл содержит определение вспомогательных шаблонов, с помощью которых | |
// можно контролировать правильность передачи параметров при вызове | |
// серверных методов (порядок, тип и значение аргументов). | |
// | |
// Подход заключается в маркировании типов аргументов с помощью | |
// тегов с метаинформацией о параметре метода (method::name, method::age и т.д.): | |
// // метаинформация | |
// struct method | |
// { | |
// struct name | |
// { | |
// // тип параметра | |
// typedef std::string type; | |
// // порядковый номер параметра | |
// enum {no = 0}; | |
// }; | |
// ... | |
// }; | |
// bool method( | |
// in<method::name> name, | |
// in<method::age> age, | |
// out<method::status> status | |
// ) | |
// | |
// Данный подход позволяет детектировать на фазе компиляции исходного кода: | |
// - нарушение порядка следования аргументов | |
// - использование значения по умолчанию для аргументов, для которых | |
// это не предусмотрено | |
// | |
// Кроме этого, повышается читаемость кода и его самодокументирование: | |
// obj.method( | |
// in<cobject::method::name>("Igor Savin"), | |
// in<cobject::method::age>(10), | |
// out<cobject::method::status>(status) | |
// ); | |
// | |
// Пример использования: | |
/*+ | |
#include <iostream> | |
#include "params.h" | |
// класс cobject генерируется по метаинформации | |
class cobject { | |
public: | |
// метаинформация о методе method | |
struct method | |
{ | |
struct name | |
{ | |
// тип параметра | |
typedef std::string type; | |
// порядковый номер параметра | |
enum {no = 0}; | |
}; | |
struct age | |
{ | |
// тип параметра | |
typedef int type; | |
// допускается значение по умолчанию | |
enum {default_value}; | |
// порядковый номер параметра | |
enum {no = 1}; | |
}; | |
struct status | |
{ | |
// тип параметра | |
typedef bool type; | |
// допускается значение по умолчанию | |
enum {default_value}; | |
// порядковый номер параметра | |
enum {no = 2}; | |
}; | |
}; | |
// сгенерированный метод | |
bool method( | |
in<method::name> name, // имя, не предусматривает значение по умолчанию | |
in<method::age> age = in<method::age>(), // возраст, предусматривает значение по умолчанию | |
out<method::status> status = out<method::status>() // status, предусматривает значение по умолчанию | |
) | |
{ | |
if( name.specified() ) { | |
// передается на сервер | |
} | |
if( age.specified() ) { | |
// передается на сервер | |
} | |
if( status.specified() ) { | |
// передается на сервер | |
} | |
// call | |
if( status.specified() ) { | |
status.set(true); | |
} | |
return true; | |
} | |
}; | |
// пример клиенского кода | |
int main(int argc, char* argv[]) | |
{ | |
cobject obj; | |
bool status = false; | |
// ошибка связанная с порядком следования: | |
obj.method( | |
in<cobject::method::age>(1), // ошибка - age стоит не на том месте | |
in<cobject::method::name>("Igor Savin") | |
); | |
// ошибка: не предусмотрено значение по умолчанию | |
obj.method( | |
in<cobject::method::name>() // ошибка: для параметра name необходимо задать значение явно | |
); | |
// корректный вызов, со значениями по умолчанию необязательных параметров | |
obj.method( | |
in<cobject::method::name>("Igor Savin") // значение должно быть задано явно | |
); | |
// корректный вызов, с явно заданными значениями для опциональных параметров | |
obj.method( | |
in<cobject::method::name>("Igor Savin"), // значение должно быть задано явно | |
in<cobject::method::age>(), // значение по умолчанию | |
out<cobject::method::status>(status) // помещаем выходное значение в локальную переменную | |
); | |
return 0; | |
} | |
-*/ | |
#ifndef ROLIS_PARAMS_H | |
#define ROLIS_PARAMS_H | |
#if _MSC_VER > 1000 | |
#pragma once | |
#endif // _MSC_VER > 1000 | |
#include <assert.h> // assert | |
/////////////////////////////////////////////////////////////////////////////// | |
// фиктивный lvalue | |
// T - тип | |
// | |
template<typename T> | |
struct fiction | |
{ | |
static T& value() { | |
static T tmp; | |
return tmp; | |
} | |
}; // struct fiction.. | |
/////////////////////////////////////////////////////////////////////////////// | |
// шаблон входного параметра | |
// P - тип, содержащий метаинформацию о параметре | |
// | |
template<typename P> | |
struct in | |
{ | |
// тип параметра | |
typedef typename P::type T; | |
public: | |
// создать входной параметр, используя значение по умолчанию | |
// если это предусмотрено для данного параметра | |
in() : value((P::default_value, 0)) | |
{ | |
} | |
// создать входной параметр, значение которое задал пользователь | |
explicit in(const T &value) : value(&value) | |
{ | |
} | |
public: | |
// задано значение? | |
bool specified() const {return (value != 0);} | |
public: | |
// селектор значения | |
const T& get() const | |
{ | |
assert(specified()); | |
return *value; | |
} | |
private: | |
const T* value; | |
}; // struct in.. | |
/////////////////////////////////////////////////////////////////////////////// | |
// шаблон выходного параметра | |
// P - тип, содержащий метаинформацию о параметре | |
template<typename P> | |
struct out | |
{ | |
// тип параметра | |
typedef typename P::type T; | |
public: | |
// создать выходной параметр, для которого не предусмотрено сохранение результата | |
out() : value((P::default_value, 0)) | |
{ | |
} | |
// создать выходной параметр с привязкой к переменной пользователя | |
explicit out(T &value) : value(&value) | |
{ | |
} | |
public: | |
// задано значение? | |
bool specified() const {return (value != 0);} | |
public: | |
// получить значение | |
const T& get() const | |
{ | |
assert(specified()); | |
return *value; | |
} | |
// присвоить значение параметру, если он задан пользователем | |
out& set(const T &other) { | |
if( specified() ) | |
*value = other; | |
return *this; | |
} | |
private: | |
T* value; | |
}; // struct out.. | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment