Этюд: значения по умолчанию
От: Кодт Россия  
Дата: 27.10.09 08:26
Оценка: +1
Здравствуйте, Kir., Вы писали:

K>Подскажите, какой компилятор сможет съесть вот такое:


Предлагаю этюд для С++гуру: сделать библиотечное решение данной проблемы.

Для целочисленных — легко
enum placeholder { _ };
// то, что он ещё и равен 0, - дополнительная фича (где-то полезная, где-то вредная)

template<class T, T V = T()> struct value
{
    T v;
    value() : v(V) {}
    value(placeholder) : v(V) {}
    template<class U> value(U u) : v(u) {}
    
    T get() const { return v; }
    operator T() const { return v; }
};

void foo(value<char,'c'> x, value<int,7> y, value<unsigned,9> z)
{
    cout << x.get() << " " << y.get() << " " << z.get() << endl;
}

int main()
{
    foo('a' , _ ,  _ );
    foo( _  , 2 ,  _ );
    foo( _  , _ , -3 );
}

( http://codepad.org/i2KUUWrc )

Как обобщить на произвольные типы? И как подсовывать по дефолту значения времени исполнения?
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>

28.10.09 14:23: Ветка выделена из темы Значения по умолчанию.
Автор: Kir.
Дата: 27.10.09
— Кодт
Перекуём баги на фичи!
Re: Этюд: значения по умолчанию
От: Alexey F  
Дата: 27.10.09 20:36
Оценка: 70 (3)
Здравствуйте, Кодт, Вы писали:

К>Предлагаю этюд для С++гуру: сделать библиотечное решение данной проблемы.

[...skip...]
К>Как обобщить на произвольные типы? И как подсовывать по дефолту значения времени исполнения?

Не гуру, но можно попробовать?

Если сделать как один класс, будет выглядеть довольно громоздко, что-то вроде:
foo ( value< char, value_int<char, 'c'> > x, value< double, value_func<double, Functor> > y ... )

(можно спрятать лишний раз указываемый тип, но, кажись, не избавимся от 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 () );
}

Стало:
00401356   |. C74424 04 6E861BF0        MOV DWORD PTR SS:[ESP+4],F01B866E                     ; |
0040135E   |. C74424 08 F9210940        MOV DWORD PTR SS:[ESP+8],400921F9                     ; |
00401366   |. C70424 24304700           MOV DWORD PTR SS:[ESP],default_.00473024              ; |ASCII "%f"
0040136D   |. E8 2EFD0100               CALL <JMP.&msvcrt.printf>                             ; \printf


Листинг получился один-в-один с:
printf ( "%f", 3.14159 );

Re: Этюд: значения по умолчанию
От: Юрий Жмеренецкий ICQ 380412032
Дата: 28.10.09 01:20
Оценка: 10 (1)
Здравствуйте, Кодт, Вы писали:


К>Для целочисленных — легко

К>
К>int main()
К>{
К>    foo('a' , _ ,  _ );
К>    foo( _  , 2 ,  _ );
К>    foo( _  , _ , -3 );
К>}
К>

К>( http://codepad.org/i2KUUWrc )

К>Как обобщить на произвольные типы? И как подсовывать по дефолту значения времени исполнения?


Можно что-то вроде этого изобразить:
template<class t> 
struct type_ { typedef t type;};

struct placeholder {} _;

template<class tag>
struct param
{
  typedef const typename tag::type type;
  param(const placeholder&) : arg(tag::get()){}
  param(type arg) : arg(arg) {}
  operator type&() { return arg; }
private:
  type arg;
};

#define PARAM(Type, Name, Value)    \
  struct Name : type_<Type> { static Type get() { return Value; } }


/////////////////////////////

PARAM(const char*, name_tag, "Bob");
PARAM(int, age_tag, 18);

void f(param<name_tag> name = _, param<age_tag> age = _)
{
  std::cout << name << ": " << age << std::endl;
}

int main()
{
  f();         // Bob: 18
  f(_, _);     // Bob: 18
  f("John", _);// John: 18
  f(_, 30);    // Bob: 30
}


Либо отказаться от списка параметров как таковых и передавать один объект — набор параметров, который можно собирать с помощью 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;'
}
Re[2]: Этюд: значения по умолчанию
От: remark Россия http://www.1024cores.net/
Дата: 28.10.09 12:29
Оценка:
Здравствуйте, Alexey F, Вы писали:

AF> func_param<std::string, SimpleGetter> b[/i] // std::string const& в такой форме уже не сделаешь


Строки можно сделать как:

s_param<'H', 'e', 'l', 'l', 'o'>



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Этюд: значения по умолчанию
От: Alexander G Украина  
Дата: 28.10.09 12:58
Оценка: +1
Здравствуйте, Кодт, Вы писали:

К>Для целочисленных — легко

enum placeholder { _ };
// то, что он ещё и равен 0, - дополнительная фича (где-то полезная, где-то вредная)


Поправка для соответствия 17.4.3.1.2

namespace { enum placeholder { _ }; }
Русский военный корабль идёт ко дну!
Re[3]: Этюд: значения по умолчанию
От: Sergey Россия  
Дата: 28.10.09 13:04
Оценка: +1 :)
Здравствуйте, 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 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[3]: Этюд: значения по умолчанию
От: Alexey F  
Дата: 28.10.09 14:53
Оценка:
Здравствуйте, remark, Вы писали:

R>Строки можно сделать как:


R>
R>s_param<'H', 'e', 'l', 'l', 'o'>

R>

R>)


Я так делал однажды (и с полной уверенностью могу заявить, что такие строки выглядят ужасно ), в процессе "изысканий" в сторону работы со строками времени компиляции. Замахнуться на perfect hash, конечно, не получилось ( ), но конкатенация, преобразование регистра, вставка в произвольное место, преобразование числа в строку в compile-time и т.п. получаются.
А, главное, можно собрать потом из этой строки обычную C-like, я раньше писал как и спрашивал (здесь
Автор: Alexey F
Дата: 29.03.09
, с велосипедными TypeList, ну да ладно), нет ли способа получше. Способа не нашлось
Re[4]: Этюд: значения по умолчанию
От: Alexey F  
Дата: 28.10.09 15:01
Оценка:
Здравствуйте, 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.

Re[5]: Этюд: значения по умолчанию
От: Sergey Россия  
Дата: 28.10.09 15:43
Оценка: +1
Здравствуйте, 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 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[6]: Этюд: значения по умолчанию
От: Кодт Россия  
Дата: 28.10.09 19:13
Оценка:
Здравствуйте, Sergey, Вы писали:

S>На практике скорее всего получатся только 2 комбинации, для BE и LE порядка байт. Ну а из 2 вариантов выбрать препроцессором нужный не особо сложно. Вот если принимать во внимание компиляторы с 16-битным int, тогда так делать точно не стоит.


Mixed endian ещё бывал (на ваксах).
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[3]: Этюд: значения по умолчанию
От: jazzer Россия Skype: enerjazzer
Дата: 28.10.09 22:28
Оценка: 22 (3)
Здравствуйте, remark, Вы писали:

R>Строки можно сделать как:


R>
R>s_param<'H', 'e', 'l', 'l', 'o'>


http://www.boost.org/libs/mpl/doc/refmanual/string.html

jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Этюд: значения по умолчанию
От: igna Россия  
Дата: 29.10.09 04:48
Оценка:
Здравствуйте, Sergey, Вы писали:

S>s_param<'Hell', 'o wo', 'rld'>


Честно говоря не понимаю, почему вышеприведенное можно предпочесть обычному:

s_param<'H','e','l','l','o',' ','w','o','r','l','d'>


Чтоб выпендренуться?
Re[5]: Этюд: значения по умолчанию
От: Sergey Россия  
Дата: 29.10.09 13:20
Оценка:
Здравствуйте, igna, Вы писали:

I>
S>>s_param<'Hell', 'o wo', 'rld'>
I>


I>Честно говоря не понимаю, почему вышеприведенное можно предпочесть обычному:


I>
I>s_param<'H','e','l','l','o',' ','w','o','r','l','d'>
I>


I>Чтоб выпендренуться?


Писать меньше и проще.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[6]: Этюд: значения по умолчанию
От: igna Россия  
Дата: 29.10.09 14:26
Оценка:
Здравствуйте, Sergey, Вы писали:

S>Писать меньше и проще.


Зато считать (до четырех) дольше. И легче потерять пробел:

s_param<'RSDN', 'это ', 'наше', ' все'>


Для сравнения:

s_param<'R','S','D','N','э','т','о',' ','н','а','ш','е',' ','в','с','е'>


И корректные варианты:

s_param<'RSDN', ' это', ' наш', 'е вс', 'е'>


s_param<'R','S','D','N',' ','э','т','о',' ','н','а','ш','е',' ','в','с','е'>


И обрати внимание на то, что нужно сделать при вставлении этого отсутствующено пробела. В нормальном случае это просто вставка четырех знаков, а в выпендронном — замена двадцати одного знака на другие двадцать шесть.
Re[7]: Этюд: значения по умолчанию
От: Sergey Россия  
Дата: 29.10.09 16:19
Оценка: 4 (1)
Здравствуйте, igna, Вы писали:

S>>Писать меньше и проще.


I>Зато считать (до четырех) дольше. И легче потерять пробел:


I>
I>s_param<'RSDN', 'это ', 'наше', ' все'>
I>


I>Для сравнения:


I>
I>s_param<'R','S','D','N','э','т','о',' ','н','а','ш','е',' ','в','с','е'>
I>


I>И корректные варианты:


I>
I>s_param<'RSDN', ' это', ' наш', 'е вс', 'е'>
I>


I>
I>s_param<'R','S','D','N',' ','э','т','о',' ','н','а','ш','е',' ','в','с','е'>
I>


I>И обрати внимание на то, что нужно сделать при вставлении этого отсутствующено пробела. В нормальном случае это просто вставка четырех знаков, а в выпендронном — замена двадцати одного знака на другие двадцать шесть.


Реальный пацанский вариант должен позволять запись вида:
s_param<'RSDN', ' ', 'это ', 'наше', ' все'>
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.