Рассмотрим следующий код в C++14
, следуя сообщениям здесь, здесь и здесь:
// Include
#include <tuple>
#include <iostream>
#include <type_traits>
// Temporary function queue declaration
template <class... F>
class temporary_function_queue;
// Apply function queue declaration
template <class... F>
constexpr temporary_function_queue<F&&...> apply_function_queue(F&&... f);
// Temporary function queue definition
template <class... F>
class temporary_function_queue final
{
// Types
private:
using const_lvalue_reference = const temporary_function_queue&;
using rvalue_reference = temporary_function_queue&&;
using temporary_type = temporary_function_queue<F&&...>;
using data_type = std::tuple<F&&...>;
// Lifecycle
private:
temporary_function_queue(rvalue_reference) = default;
temporary_function_queue(const_lvalue_reference) = delete;
temporary_function_queue operator=(rvalue_reference) = delete;
temporary_function_queue operator=(const_lvalue_reference) = delete;
explicit constexpr temporary_function_queue(F&&... f)
: _f{std::forward<F>(f)...}
{
}
// Temporary creator
public:
friend constexpr temporary_type apply_function_queue<>(F&&... f);
// Apply function queue declaration
public:
template <class... Args>
decltype(auto) operator()(Args&&... args) const&&
{
// Do I need to do std::forward on f0 too? If so, how?
return std::get<0>(_f)(std::forward<Args>(args)...);
}
// Data members
private:
data_type _f;
};
// Apply function queue definition
template <class... F>
constexpr temporary_function_queue<F&&...> apply_function_queue(F&&... f)
{
return temporary_function_queue<F&&...>(std::forward<F>(f)...);
}
/* Example of use
int main(int argc, char* argv[])
{
apply_function_queue(
[](auto i){std::cout<<0<<std::endl;},
[](auto i){std::cout<<1<<std::endl;}
)(0);
return 0;
}
*/
Цель состоит в том, чтобы создать следующий синтаксис вызова:
apply_function_queue(f0, f1, f2)(a, b, c, d, e);
Где f0, f1, f2
— это либо указатели на функции, функторы, лямбда-выражения..., а где a, b, c, d, e
— аргументы, которые должны быть идеально перенаправлены. Эта функция должна создавать временный тип, а затем вызывать operator()
этого временного типа, и этот оператор должен выполнять идеальную пересылку fn
(сейчас f0
, он будет изменен позже) с аргументами a, b, c, d, e...
. temporary_function_queue
нельзя использовать ни в каком другом контексте.
Проблема в том, что я немного запутался с переадресацией, универсальными ссылками и ссылками lvalue... Безопасен ли приведенный выше код? Если нет, то какой пример использования приведет к неопределенному поведению? И в таком случае, как сделать его безопасным и эффективным (в идеале я бы хотел, чтобы на большинстве компиляторов с -O3 не было накладных расходов во время выполнения)?
apply_function_queue()
? Подать заявкуf0(f1(f2(a, b, c, d, e)))
? или{f0(a, b, c, d, e), f1(a, b, c, d, e), f2(a, b, c, d, e)}
? - person lorro   schedule 04.02.2017f
, чтобыf(a, b, c, d, e...)
было допустимым выражением (см. сообщения, перечисленные в первой строке). - person Vincent   schedule 04.02.2017using data_type = std::tuple<F&&...>;
Это создаст кортеж идеально пересылаемых ссылок l или r-value. Не то, что вы хотите. Вы хотите отмыть это черезstd::remove_reference
. - person Sam Varshavchik   schedule 04.02.2017std::tuple<F&&...>
приведет к неопределенному поведению? - person Vincent   schedule 04.02.2017boost::hana::overload_linearly
? - person T.C.   schedule 04.02.2017temporary
_function_queue
. Хранение по значению будет другим подходом (т.е. вы можете разрешить копирование/перемещение по умолчанию и т.д.). - person Pixelchemist   schedule 04.02.2017f(a, b, c, d, e)
, вы бы просто позвонили. Поэтому я спросил: какова конечная цель, какова цель класса. - person lorro   schedule 04.02.2017