default arguments in typedef declarations
От: waev  
Дата: 21.02.13 13:08
Оценка:
коллеги,

я тут сначала наступил, а потом и в стандарте вычитал (8.3.6 Default aguments), что оказывается нельзя задавать дефолтные значения параметров при определении типа указателя на функцию.
то есть хочется писать примерно вот такой код:
typedef void (*pfun)(int a, int b = 7); // error!

void f1(int a, int b);

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

собственно, мне непонятна причина такого запрета. мне кажется, что никаких неоднозначностей тут не возникнет и вообще компилятору не составит труда такой код компилять.
в чем причина такого ограничения?

спасибо.
Re: default arguments in typedef declarations
От: zaufi Земля  
Дата: 21.02.13 13:28
Оценка:
Здравствуйте, waev, Вы писали:

W>коллеги,


W>я тут сначала наступил, а потом и в стандарте вычитал (8.3.6 Default aguments), что оказывается нельзя задавать дефолтные значения параметров при определении типа указателя на функцию.

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>

W>собственно, мне непонятна причина такого запрета. мне кажется, что никаких неоднозначностей тут не возникнет и вообще компилятору не составит труда такой код компилять.
W>в чем причина такого ограничения?

в том, что смешиваются compile-time с run-time -- информация о том какое значение у дефолтного параметра никак не отражается на сигнатуре функции.
более того, дефолтный параметр может быть очень и очень не простым (вызов конструктора к примеру, у которого тоже могут быть дефолтные параметры, у которого... ну ты понял %))
Re[2]: default arguments in typedef declarations
От: waev  
Дата: 21.02.13 13:40
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>Здравствуйте, waev, Вы писали:


W>>коллеги,


W>>я тут сначала наступил, а потом и в стандарте вычитал (8.3.6 Default aguments), что оказывается нельзя задавать дефолтные значения параметров при определении типа указателя на функцию.

W>> ...
компилятору не составит труда такой код компилять.
W>>в чем причина такого ограничения?

Z>в том, что смешиваются compile-time с run-time -- информация о том какое значение у дефолтного параметра никак не отражается на сигнатуре функции.

Z>более того, дефолтный параметр может быть очень и очень не простым (вызов конструктора к примеру, у которого тоже могут быть дефолтные параметры, у которого... ну ты понял %))

нет, я не понял. чем это принципиально отличается от объявления функции с дефолтными параметрами?

подстановку дефолтных параметров, вместе с вызовом их конструкторов, компилятор делает непосредственно при вызове функции, при чем здесь рантайм?

для вызываемой функции нет разницы были ли переданы аргументы по умолчанию или заданы явно.
Re[3]: default arguments in typedef declarations
От: Evgeny.Panasyuk Россия  
Дата: 21.02.13 14:34
Оценка:
Здравствуйте, waev, Вы писали:

W>нет, я не понял. чем это принципиально отличается от объявления функции с дефолтными параметрами?


В следующем коде
void f(int a=1){}

f — это не тип, это фактически "значение" с типом void(int).
С этим конкретным "значением", могут быть ассоциированы параметры по умолчанию, никак не влияя на тип.
#include <type_traits>

void f(int a=1){}
typedef void tf(int);

static_assert(std::is_same<decltype(f),tf>::value,"");

int main() {}
Re[3]: default arguments in typedef declarations
От: waev  
Дата: 21.02.13 14:36
Оценка:
Здравствуйте, waev, Вы писали:

W>Здравствуйте, zaufi, Вы писали:


Z>>в том, что смешиваются compile-time с run-time -- информация о том какое значение у дефолтного параметра никак не отражается на сигнатуре функции.

Z>>более того, дефолтный параметр может быть очень и очень не простым (вызов конструктора к примеру, у которого тоже могут быть дефолтные параметры, у которого... ну ты понял %))

W>нет, я не понял. чем это принципиально отличается от объявления функции с дефолтными параметрами?


W>подстановку дефолтных параметров, вместе с вызовом их конструкторов, компилятор делает непосредственно при вызове функции, при чем здесь рантайм?


W>для вызываемой функции нет разницы были ли переданы аргументы по умолчанию или заданы явно.


ну от есть.
я имею в виду, что, по-моему, с точки зрения компилятора, разницы нет, вызывать ли функцию напрямую (с указанными у нее в объявлении параметрами по умолчанию) или через указатель (с указанными в определении типа этого указателя параметрами по умолчанию).
в частности, разницы нет потому, что вызываемая функция не может отличить, были ли параметры переданы явно или их подставил туда компилятор, взяв из определения функции.
Re[3]: default arguments in typedef declarations
От: zaufi Земля  
Дата: 21.02.13 14:56
Оценка:
Здравствуйте, waev, Вы писали:

W>Здравствуйте, zaufi, Вы писали:


Z>>Здравствуйте, waev, Вы писали:


W>>>коллеги,


W>>>я тут сначала наступил, а потом и в стандарте вычитал (8.3.6 Default aguments), что оказывается нельзя задавать дефолтные значения параметров при определении типа указателя на функцию.

W>>> ...
W>компилятору не составит труда такой код компилять.

ну вот побудь компилятором чуток:
чтобы помнить, что функция имеет дефолтные параметры, нужно эту информацию заманглить в тип! чтобы когда настанет момент вызова функции, через указатель к примеру, засунытый в потроха bind'a, можно было "вспомнить" о том, что туда надо передать еще кроме того, что было передано явно, но тогда получится, что
void foo(int);
// и
void foo(int = 7);

НЕОДИНАКОВЫЕ ФУНКЦИИ -- ибо тип различется. и вообще в таком случае разрешение (resolve) перегрузок из сложного станет станет АЦЦКИ сложным (и едва ли возможным). это не говоря уже о том, что конструирование дефолтных параметров, тоже может быть далеко не тривиальным... и засунуть это в тип функции ... блин ну попробуй вот такое заманглить, раз ты умнее компилятора:
#include <iostream>

int z = 0;

int foo(int x)
{
    return 2 * x;
}

int bar(int x, int y = foo(z))
{
    return x + y;
}

int main()
{
    z = 2;
    std::cout << bar(1) << std::endl;
    return 0;
}


или вот тебе шаблон, получающий параметром callable type как это делают std алгоритмы (for_each или там transform к примеру) -- как бы ты передал им дефолтные параметры? как бы ты вообще узнал о них? из типа?

W>>>в чем причина такого ограничения?


Z>>в том, что смешиваются compile-time с run-time -- информация о том какое значение у дефолтного параметра никак не отражается на сигнатуре функции.

Z>>более того, дефолтный параметр может быть очень и очень не простым (вызов конструктора к примеру, у которого тоже могут быть дефолтные параметры, у которого... ну ты понял %))

W>нет, я не понял. чем это принципиально отличается от объявления функции с дефолтными параметрами?


template <typename F1, typename F2>
void zzz(F1, F2)
{
    std::cout << std::is_same<F1, F2>::value << std::endl;
}

void foo(int = 7);
void goo(int = 7);
void bar();
void zoo(int = 123, int = 234);

zzz(&foo, &bar); // ?
zzz(&zoo, &bar); // ?
zzz(&zoo, &foo); // ?
zzz(&zoo, &goo); // ?
...


вот чем. с точки зрения непосредственного вызова любой из этих функций -- они все воидные... им можно ничо не передавать. но здравый смысл говорит что это все разные функции с разной сигнатурой (кроме goo и foo)...

W>подстановку дефолтных параметров, вместе с вызовом их конструкторов, компилятор делает непосредственно при вызове функции, при чем здесь рантайм?


он может это сделать ТОЛЬКО при явном вызове функции... но не по указателю, потому что в типе НЕТ информации о дефолтных параметрах и как видишь ЕЕ ТАМ БЫТЬ НЕ ДОЛЖНО... иначе КАБЗДА ВСЕМУ

W>для вызываемой функции нет разницы были ли переданы аргументы по умолчанию или заданы явно.

К.О.?
Re[4]: default arguments in typedef declarations
От: Evgeny.Panasyuk Россия  
Дата: 21.02.13 15:51
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>чтобы помнить, что функция имеет дефолтные параметры, нужно эту информацию заманглить в тип!


Как вариант можно разрешить только:
void (*pf)(int a=0);

но не:
typedef void (*tf)(int a=0);

То есть примерно также как сейчас exception specifications:
void (*pf)() throw(int); // OK
typedef void (*tf)() throw(int); // Error: declared with an exception specification

Но вот я стоит ли оно того.
Re: default arguments in typedef declarations
От: pzhy  
Дата: 21.02.13 16:21
Оценка:
Здравствуйте, waev, Вы писали:

W>коллеги,


W>я тут сначала наступил, а потом и в стандарте вычитал (8.3.6 Default aguments), что оказывается нельзя задавать дефолтные значения параметров при определении типа указателя на функцию.

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>

W>собственно, мне непонятна причина такого запрета. мне кажется, что никаких неоднозначностей тут не возникнет и вообще компилятору не составит труда такой код компилять.
W>в чем причина такого ограничения?

W>спасибо.


А давай с точки зрения здравого смысла. Есть функция у которой есть default arguments, ты определяешь тип с другими, какие использовать? Даже если это разрешимо — это просто пулемет в ногу.
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);
}
Перекуём баги на фичи!
Re[2]: default arguments in typedef declarations
От: Evgeny.Panasyuk Россия  
Дата: 22.02.13 01:20
Оценка: 96 (1)
Здравствуйте, Кодт, Вы писали:

К>Чисто в качестве альтернативы — совершенно не уверен, что это решает искомую задачу, но просто для иллюстрации, что так можно делать — введём не один, а два указателя рядом

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


Если по такому пути идти, то можно и overload_set
Автор: alexeiz
Дата: 05.11.12
прикрутить,
например:
void f(int a,int b)
{
   cout << a << " " << b << endl;
}
int main()
{
   auto defaults = overload( []{f(1,2);}, bind(&f,_1,2) );
   defaults();
   defaults(3);
}

Если нужно ближе к исходной задаче, то что-то типа:
void f(int a,int b,int c)
{
   cout << a << " " << b << " " << c << endl;
}
int main()
{
    auto &&d=defaults(f,11,22,33);
    d();
    d(1);
    d(2,3);
    d(3,4,5);
}
{
    function<void(int,int,int)> general_case{f};
    auto &&d=defaults_n<3>(general_case,11,22,33);
    d();
    d(1);
    d(2,3);
    d(3,4,5);
}

Вывод:
11 22 33
1 22 33
2 3 33
3 4 5
11 22 33
1 22 33
2 3 33
3 4 5

  implementation
#include <type_traits>
#include <functional>
#include <iostream>
#include <ostream>
#include <utility>

using namespace std;

template<bool condition,typename T>
using static_if = typename enable_if<condition,T>::type;

template<typename F> struct func_args;

template<typename Result,typename ...Params>
struct func_args<Result(&)(Params...)>
{
    enum{value=sizeof...(Params)};
};

template<unsigned TotalArgs,typename Func,typename Head,typename ...Tail>
class defaults_set: defaults_set<TotalArgs,Func,Tail...>
{
    typedef defaults_set<TotalArgs,Func,Tail...> parent;
    Head data;
public:
    template<typename F,typename Arg,typename ...Args>
    defaults_set(F &&f,Arg &&arg,Args&&... args)
        : parent{forward<F>(f),forward<Args>(args)...}, data{forward<Arg>(arg)}
    {}
    template<typename ...Args>
    auto operator()(Args&&... args) ->
        static_if
        <
            sizeof...(Tail)+1+sizeof...(Args) == TotalArgs,
            typename result_of<Func(Args&&...,Head,Tail...)>::type
        >
    {
        return parent::operator()(forward<Args>(args)...,data);
    }
    using parent::operator();
};

template<unsigned TotalArgs,typename Func,typename Head>
class defaults_set<TotalArgs,Func,Head>
{
    typename conditional
    <
        is_function< typename remove_reference<Func>::type >::value,
        Func,
        typename remove_reference<Func>::type
    >::type  func;
    Head data;
public:
    template<typename F,typename Arg,typename ...Args>
    defaults_set(F &&f,Arg &&arg)
        : func{forward<F>(f)}, data{forward<Arg>(arg)}
    {}
    template<typename ...Args>
    auto operator()(Args&&... args) ->
        static_if
        <
            1+sizeof...(Args) == TotalArgs,
            decltype(func(forward<Args>(args)...,data))
        >
    {
        return func(forward<Args>(args)...,data);
    }
    template<typename ...Args>
    auto operator()(Args&&... args) ->
        static_if
        <
            sizeof...(Args) == TotalArgs,
            decltype(func(forward<Args>(args)...))
        >
    {
        return func(forward<Args>(args)...);
    }
};

template<typename Func,typename ...Args>
defaults_set<func_args<Func>::value,Func,Args...>  defaults(Func &&f,Args&&... args)
{
    return {forward<Func>(f),forward<Args>(args)...};
}

template<unsigned TotalArgs,typename Func,typename ...Args>
defaults_set<TotalArgs,Func,Args...> defaults_n(Func &&f,Args&&... args)
{
    return {forward<Func>(f),forward<Args>(args)...};
}

// _________________________________________________ //

void f(int a,int b,int c)
{
   cout << a << " " << b << " " << c << endl;
}

int main()
{
    {
        auto &&d=defaults(f,11,22,33);
        d();
        d(1);
        d(2,3);
        d(3,4,5);
    }
    {
        function<void(int,int,int)> general_case{f};
        auto &&d=defaults_n<3>(general_case,11,22,33);
        d();
        d(1);
        d(2,3);
        d(3,4,5);
    }
}

Re: default arguments in typedef declarations
От: rg45 СССР  
Дата: 22.02.13 07:35
Оценка:
Здравствуйте, waev, Вы писали:

W>я тут сначала наступил, а потом и в стандарте вычитал (8.3.6 Default aguments), что оказывается нельзя задавать дефолтные значения параметров при определении типа указателя на функцию.

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>

W>собственно, мне непонятна причина такого запрета. мне кажется, что никаких неоднозначностей тут не возникнет и вообще компилятору не составит труда такой код компилять.
W>в чем причина такого ограничения?

Потому, что если снять *только* это ограничение, не сделав больше никаких изменений в языке, то станут возможны довольно странные сценарии использования:

typedef void (*pfun1)(int a, int b = 1);
typedef void (*pfun2)(int a, int b = 2);

void f3(int a, int b = 3);

pfun1 p1 = f3; //???
pfun2 p2 = p1; //???


Какие дополнительные изменения в языке ты предлагаешь сделать, чтобы избежать этих очевидных несуразностей?
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: default arguments in typedef declarations
От: waev  
Дата: 22.02.13 07:41
Оценка:
Здравствуйте, pzhy, Вы писали:

P>А давай с точки зрения здравого смысла. Есть функция у которой есть default arguments, ты определяешь тип с другими, какие использовать? Даже если это разрешимо — это просто пулемет в ногу.


ну это-то как раз можно, правда не в одной области видимости, а в разных. в смысле, вот такой код вполне себе работает

void f(int x, int y = 5)
{
}

void a()
{
    void f(int x, int y = 2);
    f(1);
}

void b()
{
    void f(int x, int y = 7);
    f(1);
}
Re[2]: default arguments in typedef declarations
От: waev  
Дата: 22.02.13 07:54
Оценка:
Здравствуйте, rg45, Вы писали:

R>Потому, что если снять *только* это ограничение, не сделав больше никаких изменений в языке, то станут возможны довольно странные сценарии использования:


R>
R>typedef void (*pfun1)(int a, int b = 1);
R>typedef void (*pfun2)(int a, int b = 2);

R>void f3(int a, int b = 3);

R>pfun1 p1 = f3; //???
R>pfun2 p2 = p1; //???
R>


R>Какие дополнительные изменения в языке ты предлагаешь сделать, чтобы избежать этих очевидных несуразностей?


а что тут неоднозначного? типы-то у всех трех этих сущностей (p1, p2 и f3) одинаковые, различаются только дефолтные аргументы которые компилятор подставит при вызове.
по-моему всё просто, не?
Re[3]: default arguments in typedef declarations
От: rg45 СССР  
Дата: 22.02.13 08:01
Оценка:
Здравствуйте, waev, Вы писали:

R>>Потому, что если снять *только* это ограничение, не сделав больше никаких изменений в языке, то станут возможны довольно странные сценарии использования:


R>>
R>>typedef void (*pfun1)(int a, int b = 1);
R>>typedef void (*pfun2)(int a, int b = 2);

R>>void f3(int a, int b = 3);

R>>pfun1 p1 = f3; //???
R>>pfun2 p2 = p1; //???
R>>


R>>Какие дополнительные изменения в языке ты предлагаешь сделать, чтобы избежать этих очевидных несуразностей?


W>а что тут неоднозначного? типы-то у всех трех этих сущностей (p1, p2 и f3) одинаковые, различаются только дефолтные аргументы которые компилятор подставит при вызове.

W>по-моему всё просто, не?

Все верно, тип один и тот же, и неоднозначности нет. А вот насчет простоты я сомневаюсь. Мне кажется, приведенные инициализации выглядят весьма странно, затрудняют чтение кода и могут приводить к путанице.
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: default arguments in typedef declarations
От: waev  
Дата: 22.02.13 08:11
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Почему это не поддержано в стандарте?

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

ну вот я тоже к такому же мнению склоняюсь, что такую штуку можно самостоятельно на шаблонах и bind-ах реализовать, и поэтому дядьки из комитета не стали её вводить, что бы не усложнять язык.
(я просто думал, что, ну, может там может возникает какое-нибудь противоречие или неоднозначность в коде, которое мне не очевидно).
Re[3]: default arguments in typedef declarations
От: alex2013  
Дата: 22.02.13 08:58
Оценка:
Здравствуйте, waev, Вы писали:

W>Здравствуйте, Кодт, Вы писали:


К>>Почему это не поддержано в стандарте?

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

W>ну вот я тоже к такому же мнению склоняюсь, что такую штуку можно самостоятельно на шаблонах и bind-ах реализовать, и поэтому дядьки из комитета не стали её вводить, что бы не усложнять язык.

W>(я просто думал, что, ну, может там может возникает какое-нибудь противоречие или неоднозначность в коде, которое мне не очевидно).

Ну вот насчет "вводить", если верить вот этому http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Deprecated-Features.html#Deprecated-Features (The use of default arguments in function pointers, function typedefs and other places where they are not permitted by the standard is deprecated and will be removed from a future version of G++.), то в гцц это было уже достаточно давно. Ну и как мне кажется, когда поддерживаются дефолтные параметры для функций, то поддержка дефолтных параметров для указателей получается сама собой. Её наоборот специально выкорчевывать надо. Естественно, речь не идет про включение параметра в тип. Только о использовании параметра в момент вызова. Компилятор же видит объявление указателя в момент вызова, и из объявления берет дефолтные значения.

А вот причины, почему эту фичу из стандарта исключили мне не до конца понятны. Ну то есть да, единственный вариант -- это неоднозначность, которая возникает при присвоении указателей на функции с разными дефолтными параметрами.

А неоднозначность, которую можно получить если указать разные дефолтные параметры при объявлении одной и той же функции в разных единицах трансляции, просто так не исключишь. Ну то есть, если я правильно понимаю, если объявления в разных единицах трансляции, то компилятор про них никак не узнает, поэтому починить это поведение не удастся. Поэтому починили то, что смогли.

Но да, какая-то слабая версия на самом деле получается. Должен быть какой-то серьезный подводный камень при использовании дефолтных параметров у указателей.
Re[3]: default arguments in typedef declarations
От: Кодт Россия  
Дата: 22.02.13 09:07
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Если нужно ближе к исходной задаче, то что-то типа:

EP>
EP>void f(int a,int b,int c)
EP>{
EP>   cout << a << " " << b << " " << c << endl;
EP>}
EP>int main()
EP>{
EP>    auto &&d=defaults(f,11,22,33);
EP>    d();
EP>    d(1);
EP>    d(2,3);
EP>    d(3,4,5);
EP>}
EP>{
EP>    function<void(int,int,int)> general_case{f};
EP>    auto &&d=defaults_n<3>(general_case,11,22,33);
EP>    d();
EP>    d(1);
EP>    d(2,3);
EP>    d(3,4,5);
EP>}
EP>


Круто! Осталось только поддержать две вещи
— обязательные параметры
— ленивое вычисление необязательных

Это можно сделать, введя два особых типа, и обрабатывая эти типы соответственно.
auto&& d = defaults(f, mandatory, mandatory, ondemand( []()->int { foo()+bar() } )); // первые два обязательные, третий вычисляется каждый раз
Перекуём баги на фичи!
Re[4]: default arguments in typedef declarations
От: Evgeny.Panasyuk Россия  
Дата: 22.02.13 12:39
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Evgeny.Panasyuk, Вы писали:


К>
К>auto&& d = defaults(f, mandatory, mandatory, ondemand( []()->int { foo()+bar() } )); // первые два обязательные, третий вычисляется каждый раз
К>


mandatory могут идти только в начале или вперемешку? "В начале" уже работает.

Для ленивых вычислений вырисовывается отличие от обычных defaults:
struct Data
{
    int v[16];
};
 
Data &f(Data &&d=Data())
{
    return d;
}
 
void use(Data &d)
{
    d.v[0]=1;//...
}
 
int main()
{
    use(f());
}

Тут заимствуется и возвращается память со стэка вызывающей функции.
В случае с defaults_set — такой финт не пройдёт. "Заимствование" должен делать первый operator() который вызывается.
Re[5]: default arguments in typedef declarations
От: Кодт Россия  
Дата: 22.02.13 18:00
Оценка: 7 (1)
Здравствуйте, Evgeny.Panasyuk, Вы писали:

К>>
К>>auto&& d = defaults(f, mandatory, mandatory, ondemand( []()->int { foo()+bar() } )); // первые два обязательные, третий вычисляется каждый раз
К>>


EP>mandatory могут идти только в начале или вперемешку? "В начале" уже работает.


Только в начале — вперемешку непонятно, как разруливать.
А, я протупил — у тебя в defaults перечисляются только последние, необязательные аргументы. А сколько спереди обязательных — это уже следствие из сигнатуры функции.


EP>Для ленивых вычислений вырисовывается отличие от обычных defaults:

EP>Тут заимствуется и возвращается память со стэка вызывающей функции.
EP>В случае с defaults_set — такой финт не пройдёт. "Заимствование" должен делать первый operator() который вызывается.

В порядке безумной идеи: а что, если к defauls::operator() в хвост подверстать необязательный аргумент какого-то специального типа, в котором и разместить все вычисленные на месте аргументы.
Что-то вот этакое
struct the_defaults
{
  function<Data&(int,Data&&)> fun;
  function<int()> make_arg1;
  function<Data()> make_arg2;

  Data& operator() ( int i, Data&& d ) { fun(i,d); }
  Data& operator() ( int i, storage<Data> s = uninitialized ) { s.init(make_arg2()); return fun(i, s.get<0>()); }
  Data& operator() ( storage<int,Data> s = uninitialized ) { s.init(make_arg1(), make_arg2()); return fun(s.get<0>(), s.get<1>()); }
};
// где storage - это кортеж, чьи элементы конструируются не сразу, а во второй фазе;
// в роли storage<...> может пойти optional<tuple<...>>

int main()
{
  the_defaults d = { foo, []()->int{return rand();}, []()->Data{return Data(1,2,3);} };
  use(d());
}
Перекуём баги на фичи!
Re[6]: default arguments in typedef declarations
От: Evgeny.Panasyuk Россия  
Дата: 22.02.13 18:51
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Только в начале — вперемешку непонятно, как разруливать.


Я подумал про перетасовку. Например если только второй default = 111 то:
d(1,2);
d(1,2,3);

вывод:
1 111 2
1 2 3

по идее — реализуемо.

К>А, я протупил — у тебя в defaults перечисляются только последние, необязательные аргументы. А сколько спереди обязательных — это уже следствие из сигнатуры функции.


да, либо non-type template parameter в defaults_n (наверное количество аргументов у функтора можно вытащить через SFINAE).

EP>>Для ленивых вычислений вырисовывается отличие от обычных defaults:

EP>>Тут заимствуется и возвращается память со стэка вызывающей функции.
EP>>В случае с defaults_set — такой финт не пройдёт. "Заимствование" должен делать первый operator() который вызывается.
К>В порядке безумной идеи: а что, если к defauls::operator() в хвост подверстать необязательный аргумент какого-то специального типа, в котором и разместить все вычисленные на месте аргументы.
К>Что-то вот этакое
[...]
К>// где storage — это кортеж, чьи элементы конструируются не сразу, а во второй фазе;
К>// в роли storage<...> может пойти optional<tuple<...>>

Согласен, по идее должно взлететь
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.