Здравствуйте, Кодт, Вы писали:
К>Предлагаю этюд для С++гуру: сделать библиотечное решение данной проблемы.
[...skip...] К>Как обобщить на произвольные типы? И как подсовывать по дефолту значения времени исполнения?
Не гуру, но можно попробовать?
Если сделать как один класс, будет выглядеть довольно громоздко, что-то вроде:
(можно спрятать лишний раз указываемый тип, но, кажись, не избавимся от value< ..., value_... <...> >).
Следовательно, разделяем классы:
...
#include <cmath>
enum placeholder { _ }; // Нехорошо, наверное (:xz:), нижним подчёркиванием, но оставим так для чистоты в коде примера.
// Целые значения:
// (оставил почти без изменений)template<class T, T V = T()>
struct i_param // integer parameter
{
i_param () : value(V) {}
i_param (placeholder) : value(V) {}
template<class U> i_param (U u) : value(u) {}
T get() const { return value; }
operator T() const { return value; }
T value; // оставим открытым на случай, если надо будет адрес взять, например.
};
// Дробные значения:
// Вспомогательный код:namespace aux {
// long/long long по вкусуtypedef long long integral_part;
typedef unsigned long long rational_part;
template<rational_part number>
struct digits_in_number {
enum { result = 1 + digits_in_number<number / 10>::result };
};
template<>
struct digits_in_number<0> {
enum { result = 0 };
};
}
template<class T, aux::integral_part Integral, aux::rational_part Rational>
struct f_param { // float parameter
f_param () : value ( makeValue () ) {}
f_param ( placeholder ) : value ( makeValue () ) {}
template<class U>
f_param ( U const& other )
: value ( other ) {}
T get () const {
return value;
}
operator T () const {
return value;
}
T value;
private:
inline T makeValue () const {
return
( std::abs ( static_cast<T> ( Integral ) ) + ( Rational * std::pow ( 10, -aux::digits_in_number<Rational>::result ) ) )
* ( Integral >= 0 ? 1 : -1 )
;
}
};
// Ну и, наконец, произвольные значения (в том числе и времени выполнения), которые получаются через функтор
// (только вот параметры ему не передашь):template<class T, class Functor>
struct func_param { // functor parameter
func_param () : value ( Functor ()() ) {}
func_param ( placeholder ) : value ( Functor ()() ) {}
template<class U>
func_param ( U const& other )
: value ( other ) {}
T const& get () const {
return value;
}
operator T const& () const {
return value;
}
T value;
};
Пример использования:
...
struct SimpleGetter {
std::string operator ()() const {
return"test";
}
};
void foo (
i_param<char, 'c'> x,
i_param<int, 7> y,
i_param<unsigned, 9> z,
f_param<double, 3,14> a, // запятая, а не точка!
func_param<std::string, SimpleGetter> b// std::string const& в такой форме уже не сделаешь :)
)
{
cout << x.get() << " " << y.get() << " " << z.get() << ' ' << a.get () << ' ' << b.get () << endl;
}
int main()
{
foo('a', _, _, _, _ );
foo( _, 2, _, _, "test 2" );
foo( _, _, -3, 3.14159, _ );
}
Результат:
a 7 9 3.14 test
c 2 9 3.14 test 2
c 7 4294967293 3.14159 test
P.S. У кого сомнения насчёт pow, abs в f_param то gcc 4.4.1 (да и используемый мной более старый, если не изменяет память) в -O2 их оптимизирует до подсовывания константы:
Было:
...
int main () {
printf ( "%f", f_param<double, 3,14159> ().get () );
}
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Alexey F, Вы писали:
AF>> func_param<std::string, SimpleGetter> b[/i] // std::string const& в такой форме уже не сделаешь
R>Строки можно сделать как:
R>
R>s_param<'H', 'e', 'l', 'l', 'o'>
R>
R>) R>
Думая при определенном занудстве получится даже группировать символы по 4
Типа такого:
s_param<'Hell', 'o wo', 'rld'>
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Либо отказаться от списка параметров как таковых и передавать один объект — набор параметров, который можно собирать с помощью expression templates (синтаксис вызова немного изменится). Другой способ читерский, — взять boost.parameter, он поддерживает именованные параметры:
#include <boost/parameter/name.hpp>
#include <boost/parameter/preprocessor.hpp>
BOOST_PARAMETER_NAME(name)
BOOST_PARAMETER_NAME(age)
BOOST_PARAMETER_FUNCTION((void), foo, tag,
(optional (name,(const char*), "Bob")(age, (int), 18)))
{
std::cout << name << " : " << age << std::endl;
}
int main() {
foo(); // Bob : 18
foo(_name = "John"); // John : 18
foo(_age = 30); // Bob : 30
foo(_age = 25, _name = "Alice"); // Alice : 25
foo(_name = "Alice", _age = 25); // Alice : 25
// оптимизатор msvc производит такой же код как и в случае
// 'std::cout << "X" << " : " << Y << std::endl;'
}
I>И обрати внимание на то, что нужно сделать при вставлении этого отсутствующено пробела. В нормальном случае это просто вставка четырех знаков, а в выпендронном — замена двадцати одного знака на другие двадцать шесть.
Реальный пацанский вариант должен позволять запись вида:
s_param<'RSDN', ' ', 'это ', 'наше', ' все'>
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, Alexey F, Вы писали:
S>>Думая при определенном занудстве получится даже группировать символы по 4 S>>Типа такого: S>>
S>>s_param<'Hell', 'o wo', 'rld'>
S>>
AF>Только при расщеплении на отдельные символы столкнёмся с тем, что у multicharacter literal значение — implementation-defined, AF>т.е. какие там буквы в каком порядке будут — ...: AF>
AF>2.13.2 Character literals
AF>1 A character literal is one or more characters enclosed in single quotes, as in ’x’, optionally preceded by
AF>the letter L, as in L’x’. A character literal that does not begin with L is an ordinary character literal, also
AF>referred to as a narrow-character literal. An ordinary character literal that contains a single c-char has type
AF>char, with value equal to the numerical value of the encoding of the c-char in the execution character set.
AF>An ordinary character literal that contains more than one c-char is a multicharacter literal. A multicharacter
AF>literal has type int and implementation-defined value.
На практике скорее всего получатся только 2 комбинации, для BE и LE порядка байт. Ну а из 2 вариантов выбрать препроцессором нужный не особо сложно. Вот если принимать во внимание компиляторы с 16-битным int, тогда так делать точно не стоит.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, remark, Вы писали:
R>Строки можно сделать как:
R>
R>s_param<'H', 'e', 'l', 'l', 'o'>
R>
R>)
Я так делал однажды (и с полной уверенностью могу заявить, что такие строки выглядят ужасно ), в процессе "изысканий" в сторону работы со строками времени компиляции. Замахнуться на perfect hash, конечно, не получилось ( ), но конкатенация, преобразование регистра, вставка в произвольное место, преобразование числа в строку в compile-time и т.п. получаются.
А, главное, можно собрать потом из этой строки обычную C-like, я раньше писал как и спрашивал (здесь
Здравствуйте, Sergey, Вы писали:
S>Думая при определенном занудстве получится даже группировать символы по 4 S>Типа такого: S>
S>s_param<'Hell', 'o wo', 'rld'>
S>
Только при расщеплении на отдельные символы столкнёмся с тем, что у multicharacter literal значение — implementation-defined,
т.е. какие там буквы в каком порядке будут — ...:
2.13.2 Character literals
1 A character literal is one or more characters enclosed in single quotes, as in ’x’, optionally preceded by
the letter L, as in L’x’. A character literal that does not begin with L is an ordinary character literal, also
referred to as a narrow-character literal. An ordinary character literal that contains a single c-char has type
char, with value equal to the numerical value of the encoding of the c-char in the execution character set.
An ordinary character literal that contains more than one c-char is a multicharacter literal. A multicharacter
literal has type int and implementation-defined value.
Здравствуйте, Sergey, Вы писали:
S>На практике скорее всего получатся только 2 комбинации, для BE и LE порядка байт. Ну а из 2 вариантов выбрать препроцессором нужный не особо сложно. Вот если принимать во внимание компиляторы с 16-битным int, тогда так делать точно не стоит.
И обрати внимание на то, что нужно сделать при вставлении этого отсутствующено пробела. В нормальном случае это просто вставка четырех знаков, а в выпендронном — замена двадцати одного знака на другие двадцать шесть.