LINUX.ORG.RU

Чё ей надо?

 ,


0

3
#include <functional>

struct R {};
template<class... PP> void f(std::function<R(PP...)>) {}

struct P {};

int main() {
	// No matching function for call to 'f'.
	// Candidate template ignored: could not match 'std::function<R (PP...)>' against '(lambda at ...)'
	f([&](P) { return R{}; });

	// То же самое.
	// UPD: Впрочем, не совсем: тут could not match 'std::function<R (P, PP...)>'. Бред какой-то.
	f<P>([&](P) -> R { return R{}; });
}

★★★★★

Последнее исправление: dimgel (всего исправлений: 1)

Ответ на: комментарий от annulen

Уже и сам вспомнил, что к std::function что только не приводится – и обычные функции, и функции-члены… Блин, ну и бардак. Что-то не прёт у меня сегодня вообще.

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

Это не бардак, это ровно то, для чего std::function предназначена - унифицированный тип переменной, в которой можно сохранить любую вызываемую сущность подходящей сигнатуры

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

По твоей первой ссылке это есть, со static_assert(), и если мне от функтора нужно проверять только тип возвращаемого значения, наверное можно найти какие-нибудь type-traits чтобы избежать <class F, class...PP>. Потому что эта дрянь даже такое не хочет: void f(std::function<R(auto...)>) {}.

Но я по-прежнему не втыкаю, почему второй вариант в ТС с явным указанием f<P> не работает, да ещё какую-то дикую сигнатуру function<R(P, PP)> выводит.

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

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

Но я по-прежнему не втыкаю, почему второй вариант в ТС с явным указанием f не работает, да ещё какую-то дикую сигнатуру function<R(P, PP)> выводит.

   // правильно так
   f(std::function([&](P) -> R { return R{}; }));

Во время поиска подходящего шаблона никакие приведения типов не допускаются, здесь всё строже. Потом все подходящие шаблоны + не шаблоны попадают в общий overload set и вызывается самый подходящий со всеми обычными кастами. Блин, букварь, первый класс.

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

Осиль концепты, включай шаблон только когда аргумент соответствует критериям, никакого std::function при вызове тогда писать не придется.

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

Местами использую. Но в данном кейсе это будет по сути примерно то же, что и static_assert() по ссылке в первом каменте, и секса будет не намного меньше. Пока что пробую другой финт ушами.

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

На таком «шикарном» синтаксисе хоть сколько-нибудь юзабельный DSL не сделать.

Вот тебе DSL #1:

#define FUN std::function

int main() {
    f(FUN([&](P) { return R{}; }));
}

Вот тебе DSL #2:

#define FUN(...) std::function([&](P) { __VA_ARGS__ })

int main() {
    f(FUN(return R{};));
}

И т.д., на сколько фантазии хватит

annulen ★★★★★
()
Ответ на: комментарий от annulen
  1. На препроцессор душа категорически не лежит.

  2. А вот эквивалентный вызов на скале (ЕМНИП, давно не юзал): f(p -> R()).

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

На препроцессор душа категорически не лежит.

Без препроцессора про eDLS в C++ можно даже не думать

А вот эквивалентный вызов на скале (ЕМНИП, давно не юзал)

С++ не проектировался как функциональный ЯП, да и заменить ФП-языки вроде Scala и Haskell в их нише он все равно никогда не сможет из-за отсутствия GC.

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

Без препроцессора про eDLS в C++ можно даже не думать

С чего бы это? https://github.com/foonathan/lexy

namespace dsl = lexy::dsl;

// Parse an IPv4 address into a `std::uint32_t`.
struct ipv4_address
{
    // What is being matched.
    static constexpr auto rule = []{
        // Match a sequence of (decimal) digits and convert it into a std::uint8_t.
        auto octet = dsl::integer<std::uint8_t>;

        // Match four of them separated by periods.
        return dsl::times<4>(octet, dsl::sep(dsl::period)) + dsl::eof;
    }();

    // How the matched output is being stored.
    static constexpr auto value
        = lexy::callback<std::uint32_t>([](std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d) {
            return (a << 24) | (b << 16) | (c << 8) | d;
        });
};
dataman ★★★★★
()
Ответ на: комментарий от dimgel

Секса тут не много, тривиальная конструкция, программиста на плюсах такое не должно пугать.

template <typename T> struct Check;
template <typename Rt, typename... A>
struct Check<function<Rt(A...)>> {	
	static constexpr bool v = is_same_v<Rt, R>;
};

template<class PP> 
requires Check<decltype(function(declval<PP>()))>::v
void f(PP &&) {}

При том, что function заюзана лишь в компайл тайме, а не как у тебя. std::function не юзается в норме в параметрах шаблонных функций.

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

Спасибо, заюзал и даже понял, и в concept завернул. Хотя если это

тривиальная конструкция

то я балерина Большого театра (UPD: у которой ноги не сходятся).

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