Skip to content

Instantly share code, notes, and snippets.

@anatoly-spb
Created February 20, 2018 10:08
Show Gist options
  • Save anatoly-spb/7afed6e575e024905b11e53111a26b0d to your computer and use it in GitHub Desktop.
Save anatoly-spb/7afed6e575e024905b11e53111a26b0d to your computer and use it in GitHub Desktop.
Tagging
///////////////////////////////////////////////////////////////////////////////
// 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