Чтобы завершить ответы моего коллеги, вы можете обратить пристальное внимание на:
Вот старый код java1.4, который учитывает эти моменты:
/**
* Allow for instance call, avoiding certain class circular dependencies.
* Calls even private method if java Security allows it.
* @param aninstance instance on which method is invoked (if null, static call)
* @param classname name of the class containing the method
* (can be null - ignored, actually - if instance if provided, must be provided if static call)
* @param amethodname name of the method to invoke
* @param parameterTypes array of Classes
* @param parameters array of Object
* @return resulting Object
* @throws CCException if any problem
*/
public static Object reflectionCall(final Object aninstance, final String classname, final String amethodname, final Class[] parameterTypes, final Object[] parameters) throws CCException
{
Object res;// = null;
try {
Class aclass;// = null;
if(aninstance == null)
{
aclass = Class.forName(classname);
}
else
{
aclass = aninstance.getClass();
}
//Class[] parameterTypes = new Class[]{String[].class};
final Method amethod = aclass.getDeclaredMethod(amethodname, parameterTypes);
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
amethod.setAccessible(true);
return null; // nothing to return
}
});
res = amethod.invoke(aninstance, parameters);
} catch (final ClassNotFoundException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+CLASS, e);
} catch (final SecurityException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_SECURITY_ISSUE, e);
} catch (final NoSuchMethodException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_NOT_FOUND, e);
} catch (final IllegalArgumentException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ILLEGAL_ARGUMENTS+String.valueOf(parameters)+GenericConstants.CLOSING_ROUND_BRACKET, e);
} catch (final IllegalAccessException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ACCESS_RESTRICTION, e);
} catch (final InvocationTargetException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_INVOCATION_ISSUE, e);
}
return res;
}
Насколько я понимаю, свойства потока, которые вы Повторное использование для указания типов было бы более подходящим для указания порядка байтов, упаковки или других значений «метаданных». Обработка самих типов должна выполняться компилятором. По крайней мере, именно так выглядит STL.
Если вы используете перегрузки для автоматического разделения типов, вам нужно будет указать тип только в том случае, если он отличается от объявленного типа переменной:
Stream& operator<<(int8_t);
Stream& operator<<(uint8_t);
Stream& operator<<(int16_t);
Stream& operator<<(uint16_t);
etc.
uint32_t x;
stream << x << (uint16_t)x;
Чтение типы, отличные от объявленного, будут немного сложнее. В целом, однако, я думаю, следует избегать чтения или записи переменных типа, отличного от типа вывода.
Я считаю, что стандартная версия std :: codecvt ничего не делает, возвращая "noconv" для всего. Он действительно что-то делает только при использовании «широких» символьных потоков. Можно' Вы установили аналогичное определение для codecvt? Если по какой-то причине нецелесообразно определять для вашего потока безоперационный codecvt, то я не вижу никаких проблем с вашим решением для литья, тем более что оно изолировано в одном месте.
Наконец, вы уверены, что не стали бы Не лучше ли использовать какой-нибудь стандартный код сериализации, например Boost , чем накатывать свой собственный?
Нам нужно было сделать что-то похожее на то, что делаете вы, но мы пошли другим путем. Мне интересно, как вы определили свой интерфейс. Часть того, с чем я не знаю, как вы справитесь, - это манипуляторы , которые вы определили (binary :: u32le, binaryu16le).
С помощью basic_streams манипулятор управляет тем, как будут считываться все следующие элементы / написано, но в вашем случае это, вероятно, не имеет смысла, поскольку размер (часть информации вашего манипулятора) зависит от входящей и исходящей переменной.
binary_istream in;
int i;
int i2;
short s;
in >> binary::u16le >> i >> binary::u32le >> i2 >> s;
В приведенном выше коде может иметь смысл определить, будет ли переменная i
- 32 бита (при условии, что int - 32 бита), вы хотите извлечь из сериализованного потока только 16 бит, а вы хотите извлечь все 32 бита в i2
. После того,
Я бы не стал использовать оператор <<, поскольку он слишком тесно связан с вводом-выводом форматированного текста.
Я бы вообще не стал использовать для этого перегрузку оператора. Я бы нашел другую идиому.
Я согласен с Legalize. Мне нужно было делать почти то же самое, что и вы, и я посмотрел на перегрузку <<
/ >>
, но пришел к выводу, что iostream просто не предназначен для этого. Во-первых, я не хотел создавать подклассы потоковых классов, чтобы иметь возможность определять свои перегрузки.
Мое решение (которое требовало только временной сериализации данных на одной машине и, следовательно, не требовало обращения к порядку следования байтов) было основано на следующем шаблоне:
// deducible template argument read
template <class T>
void read_raw(std::istream& stream, T& value,
typename boost::enable_if< boost::is_pod<T> >::type* dummy = 0)
{
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
}
// explicit template argument read
template <class T>
T read_raw(std::istream& stream)
{
T value;
read_raw(stream, value);
return value;
}
template <class T>
void write_raw(std::ostream& stream, const T& value,
typename boost::enable_if< boost::is_pod<T> >::type* dummy = 0)
{
stream.write(reinterpret_cast<const char*>(&value), sizeof(value));
}
Затем я дополнительно перегрузил read_raw / write_raw для любых типов, отличных от POD ( например, струны). Обратите внимание, что необходимо перегружать только первую версию read_raw; если вы правильно используете ADL , вторая версия (с 1 аргументом) может вызывать перегрузки с 2 аргументами, определенные позже и в других пространствах имен.
Пример записи:
int32_t x;
int64_t y;
int8_t z;
write_raw(is, x);
write_raw(is, y);
write_raw<int16_t>(is, z); // explicitly write int8_t as int16_t
Пример чтения:
int32_t x = read_raw<int32_t>(is); // explicit form
int64_t y;
read_raw(is, y); // implicit form
int8_t z = numeric_cast<int8_t>(read_raw<int16_t>(is));
Это не так привлекательно, как перегруженные операторы, и что-то не так легко помещается в одну строку (чего я все равно стараюсь избегать, поскольку точки останова отладки ориентированы на строки) , но, думаю, получилось проще, нагляднее и не намного многословнее.