Re: default arguments in typedef declarations
От: Кодт Россия  
Дата: 21.02.13 22:44
Оценка: 1 (1)
Здравствуйте, waev, Вы писали:

W>то есть хочется писать примерно вот такой код:

W>
W>typedef void (*pfun)(int a, int b = 7); // error!

W>void f1(int a, int b);

W>void main(){
W>    pfun f = f1;
W>    f(1);
W>}
W>


Конкретно здесь можно написать хитроумный указатель-на-функцию
struct pfun
{
  typedef void result_type; // для std::bind
  typedef result_type (*ptr_type)(int,int);
  ptr_type p;
  pfun(ptr_type p) : p(p) { assert(p); }
  result_type operator() (int a, int b=7) const { return (*p)(a,b); }
};

Фактически, это мы дали уникальное имя типу void(int,int=7). И завернули туда вычисление необязательных аргументов. Сделали работу за компилятора.
Правда, мы не можем теперь привести pfun обратно к void(int,int) или void(int), или к точно такой же структуре, но под другим именем, — но можем привести и к std::function<void(int,int)>, и к std::function<void(int)>.

Почему это не поддержано в стандарте?
Во-первых, потому же, почему голый сишный указатель на функцию нельзя получить из std::function (наоборот — можно). Здесь не только семейство сигнатур описывается (void(int), void(int,int)), но и выражения для вычисления аргументов. А это уже в один указатель не вместится. Либо это будет указатель не на функцию, а на таблицу функций, или на какой-нибудь хитрый диспетчерский код. И никакой совместимости со старым добрым Си.
Во-вторых, поддержка этой фичи — это синтаксический сахар, сравнимый по объёму с лямбдами. Сколько лет потребовалось, чтобы лямбды в стандарт вошли? Сколько потребуется, чтобы ввести полиморфные лямбды? Вот то-то же. Если очень хочется, — нужно писать заявку в комитет и в ньюсгруппу.

Но это всё возвышенные рассуждения.
Практически, если такую фичу захотелось в конкретном месте, — то нужно глядеть в корень: ЗАЧЕМ её захотелось. Возможно, что там есть другие и не менее изящные решения в рамках нынешних возможностей.

Чисто в качестве альтернативы — совершенно не уверен, что это решает искомую задачу, но просто для иллюстрации, что так можно делать — введём не один, а два указателя рядом
void f1(int,int);
void f2(int,int);

int main()
{
  void (*ff)(int,int) = (rand()%2 ? f1 : f2); // если мы захотим вызывать с 2 аргументами
  std::function<void(int)> f = std::bind(ff, _1, 7); // если захотим вызывать с 1 аргументом
  // если ff не нужен сам по себе - просто подставим его внутрь bind

  f(1);
  ff(1,2);
}
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.