LINUX.ORG.RU

Двойные скобки С++

 


0

2

Доброго времени суток!

Как сделать так, чтобы в прогах можно было пользоваться синтаксисом наподобие boost::bind: boost::bind(compare, _1, _2)(a, b);?

То есть как писать функции с двумя скобками f(a)(b)?

★★

Просто функция bind возвращает тип, у которого определен operator()

m0rph ★★★★★ ()
Ответ на: комментарий от m0rph

А можно простой пример, как это реализовать?

aido ★★ ()
Ответ на: комментарий от aido

Ну например так:

#include <iostream>

class Foo {
public:
    int operator()() const
    {
        return 42;
    }
};

Foo f()
{
    return Foo();
}

int main()
{
    std::cout << f()() << std::endl;
    return 0;
}

m0rph ★★★★★ ()
Последнее исправление: m0rph (всего исправлений: 2)
#include <iostream>
#include <functional>

std::function<int(int)>
f(int a) {
	return [a](int b) {
		return a + b;
	};
}

int
main(void)
{
	std::cout << "f(2)(3) = " << f(2)(3) << std::endl;
	return 0;
}
i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

В C++14 вроде бы можно чуть опрятнее:

#include <iostream>

decltype(auto)
f(int a) {
	return [a](int b) {
		return a + b;
	};
}

int
main(void)
{
	std::cout << "f(2)(3) = " << f(2)(3) << std::endl;
	return 0;
}
i-rinat ★★★★★ ()
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от i-rinat

А с конструкторами классов такое же можно делать? В смысле, если экземпляр одного класса является полем другого класса и хочется вызвать конструктор второго класса примерно так Cl2 abc(arguments of the first class)(arguments of the second class)

aido ★★ ()
Ответ на: комментарий от aido

Можно сделать нечто подобное и с конструктором. Здесь сначала создается временный объект класса Foo, а потом у этого объекта вызывается operator()(int):

#include <iostream>

class Foo {
public:
    int operator()(int value) const
    {
        return value;
    }
};

int main()
{
    std::cout << Foo()(20) << std::endl;
    return 0;
}

m0rph ★★★★★ ()
Последнее исправление: m0rph (всего исправлений: 1)
Ответ на: комментарий от aido

Недочитал твое сообщение. Вообще можно конечно сделать что-то похожее, только это какое-то непонятно зачем нужное извращение:

#include <iostream>

class Bar {
public:
    Bar(int value) :
        value_(value)
    {
    }

    int f() const
    {
        return value_;
    }

private:
    int value_;
};

class Foo {
public:
    Foo(int value)
    {
    }

    Bar operator()(int value) const
    {
        return Bar(value);
    }
};

int main()
{
    Bar bar = Foo(30)(20);
    std::cout << bar.f() << std::endl;
    return 0;
}

m0rph ★★★★★ ()
Последнее исправление: m0rph (всего исправлений: 1)
Ответ на: комментарий от m0rph

Я имею ввиду нечто подобное (этот код точно не будет рабочим, но идея взаимосвязи классов, думаю, более менее ясна):

#include <iostream>

class Foo {
public:
    Foo(int value)
    {
        std::cout<<value<<std::endl;
    }
};

class Bar {
private:
    Foo f;
public:
    int operator(int value1)(int value2) const
    {
        f(value1);
        std::cout<<value2<<std::endl;
    }
};

int main()
{
    Bar b(20)(40);
    return 0;
}

aido ★★ ()

Как сделать так, чтобы в прогах можно было пользоваться синтаксисом

бери и пользуйся

наподобие boost::

У тебя это пройдет :) Криптопослания из смайликов в коде типа x::()()() о_О ()/().()/(), где о_О тоже оператор ничего кроме о_О у случайно заглянувших в твой код не вызовут... А у тех, кто будет сопровождать - ничего кроме ненависти и желания «дропнуть это г*но и все тут переписать». Но можно ж на крайняк подсмотреть прям в бусте :)

slackwarrior ★★★★★ ()
Ответ на: комментарий от aido

Сделай в конструкторе Bar два аргумента и инициализируй внутренний Foo одним из них.

m0rph ★★★★★ ()
Ответ на: комментарий от slackwarrior

Вопрос сопровождения в первую очередь относится к документированию кода. Ясен пень, что если использовать такие наборы смайликов, то дропнуть захочется любому, но мне хватит пока что только Bar b(arg1)(arg2), а это очень просто описать словами, на кой черт такое понадобилось.

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

То есть код был бы примерно таким:

#include <iostream>

class Foo {
public:
    Foo(int value)
    {
        std::cout<<value<<std::endl;
    }
};

template <class T>class Bar {
private:
    T f;
public:
    int operator(int value1)(int value2) const
    {
        f(value1);
        std::cout<<value2<<std::endl;
    }
};

int main()
{
    Bar<Foo> b(20)(40);
    return 0;
}

Вопрос касается в первую очередь числа и типов аргументов, подаваемых в первый класс (Bar как бы не особо знает, для какого класса он будет оберткой и какие аргументы ему нужны...).

aido ★★ ()
Ответ на: комментарий от i-rinat

Это конечно придирка, но в коде такого уровня дико смотрятся «void» и «return 0».

anonymous ()
Ответ на: комментарий от anonymous

Я на сях пишу, у меня main(void по привычке набирается. То же и с return.

i-rinat ★★★★★ ()
Ответ на: комментарий от asaw

Он просто ненужен. Анси-сишное легаси в шаге от наворотов C++14, ужас.

anonymous ()
Ответ на: комментарий от i-rinat

Они и в сях давно не нужны.

/* Извиняюсь за офтоп */

anonymous ()
Ответ на: комментарий от anonymous

Вовсе нет. Необязательность return'а из int фунции, причём только для одной единственной — в чём польза этого усложнения? Меньше набирать для примеров кода на форумах?

i-rinat ★★★★★ ()

В c++11 вполне реально написать функцию curry, которая из произвольной функции делает каррированную.

Kuzy ★★★ ()

Мне кажется, или товарищ хочет каррирование?

hateyoufeel ★★★★★ ()
Ответ на: комментарий от i-rinat

Меньше набирать для примеров кода на форумах?

А этого недостаточно? Очень частый юзкейс.

anonymous ()

Нужно больше скобок!

ados ★★★★★ ()
Ответ на: комментарий от i-rinat

И с какого это времени?

return - C99, main() афаик всегда можно было, ибо пустые скобки в определении означают отсутствие параметров, как и (void).

в чём польза этого усложнения? Меньше набирать для примеров кода на форумах?

В том числе :) В любом случае, так есть.

anonymous ()
Ответ на: комментарий от anonymous

В с пустые скобки без воид это не воид. Не как как в спп

anonymous ()

На кой это понадобилось?! Если в бусте по другому нельзя, то зачем «притягивать за уши» язык, построенный на языке? Чтобы у коллег разрыв мозга лишний раз случился?

anonymous ()
Ответ на: комментарий от anonymous

return - C99

Мда, действительно. А я всё время думал, что только в C++ можно.

пустые скобки в определении означают отсутствие параметров, как и (void)

В более старых сях пустые скобки означали функцию с произвольным числом аргументов. И gcc -std=c99 -pedantic тоже так считает. В стандарте с наскоку не нашлось.

i-rinat ★★★★★ ()

Неплохой пример удобного использования этого можно увидеть в boost::program_options, например в методе options_description::add_options, который возвращает объект класса options_description_easy_init, у которого перегружен оператор (), который возвращает объект того же класса. Что позволяет делать сколь угодно длинные списки опций в простом декларативном формате:

po::options_description desc("Allowed options");
desc.add_options()
    ("help", "produce help message")
    ("optimization", po::value<int>(&opt)->default_value(10), "optimization level")
    ("include-path,I", po::value< vector<string> >(), "include path")
    ("input-file", po::value< vector<string> >(), "input file")
;

CatsCantFly ()

Я думаю aido понравится Objective-C. Там очень много скобочек, каждый аргумент имеет название, просто идеальный язык.

yurikoles ★★★ ()
Последнее исправление: yurikoles (всего исправлений: 1)
Ответ на: комментарий от i-rinat

C99: 6.7.5.3.14

An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.

anonymous ()
Ответ на: комментарий от anonymous

Угу, но от этого астрологи объявляют неделю K&R. Число предупреждений сокращается вдвое.

i-rinat ★★★★★ ()
Ответ на: комментарий от CatsCantFly

Ну да. Я хочу каррирование, но с конструкторами шаблонных классов.

aido ★★ ()
Ответ на: комментарий от CatsCantFly

Лучше уж через initializer_list сделать. А то всякие анализаторы кода не думаю, что ожидают такого использования оператора ()

Gorthauer ★★★★★ ()
Ответ на: комментарий от aido

operator() можно же делать шаблонным. В чем собственно сложность?

Gorthauer ★★★★★ ()
Ответ на: комментарий от Gorthauer

Да я пока только изучаю возможности с++11.

а причем здесь шаблонный оператор ()? Тут основная проблема в том, что конструктор ничего не возвращает, поэтому нельзя писать нечто вроде TMyClass abc(1,2,3)(4,5,6), чтобы аргументы из вторых скобок падали в конструктор другого класса.

aido ★★ ()
Ответ на: комментарий от Gorthauer

Нельзя через initializer_list сделать. Во первых - там аргументы разных типов, во вторых - надо контролировать их определенное количество.

CatsCantFly ()
Ответ на: комментарий от aido

Я, конечно, не знаю, зачем тебе это извращение нужно, но ты хочешь что-то вроде такого? (насчет синтаксиса не уверен)

template <typename AnyType>
class my_class {
public:
  my_class() {}
    
  template <typename ...ArgsList>
  AnyType operator() (ArgsList ... args)
  {
    return AnyType(args...);
  }
};
Вопрос только - зачем это нужно?

anonymous ()
Ответ на: комментарий от aido

В оператор () попасть они могут, а он выглядит как вызов конструктора.

Gorthauer ★★★★★ ()

А чё только двойные? Хуярь сразу тройные, а лучше четверные.

anonymous ()

boost::bind

std::bind

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.