#c #templates #c 14 #auto
Вопрос:
Я использую веб-фреймворк C , который в значительной степени использует лямбда-функции обратного вызова. Как вы можете догадаться, параметры для лямбд обычно задаются как auto
из-за необходимости объявлять очень длинные объявления.
Теперь я использую decltype()
оператор для поиска правильного типа, выведенного с помощью auto
, чтобы я мог объявить вектор того же типа. Когда объявление вектора происходит внутри лямбды, все в порядке.
Моя проблема начинается с того, что этот вектор должен быть объявлен во внешней области, используя auto
информацию о типе параметров lambdas. Ниже приведен простой пример:
std::vector<T> vec; // I want the type information to be inferred just like vec2 from lambda below
auto func = [](auto parameter){
std::vector<decltype(parameter)> vec2; // No problem here.
};
Возможно ли это?
Обновить:
Структура, которую я использую, такова uWebSockets
. Вот пример кода :
using DataType = std::string;
// I had to go get type information from the source code.
static std::vector<uWS::WebSocket<false, true, DataType> *> users;
uWS::App app {};
app.ws<DataType>("/*", {
.open = [](auto * ws){
// This is also doable
// But not accessible in other lambdas.
static std::vector<decltype(ws)> users2;
// users2.push_back(ws);
users.push_back(ws);
ws->subscribe("sensors/ /house");
},
.close = [](auto *ws, int code, std::string_view message){
users.erase(std::remove(users.begin(), users.end(), ws), users.end());
// Not possible because not accessible.
//users2.erase(std::remove(users2.begin(), users2.end(), ws), users2.end());
std::cout << "Client disconnected!" << std::endl;
},
.message = [](auto *ws, std::string_view message, uWS::OpCode opCode){
try{
std::string message2 = std::string(message) std::string(" ACK");
for(const auto amp; ws2 : users)
if(ws != ws2)
ws2->send(message2, opCode);
}catch(std::exceptionamp; e){
std::cout << e.what() << std::endl;
}
},
});
Теперь, нигде в main.cpp
, нет необходимости передавать параметр в лямбда-функции. Вот откуда берется главная проблема.
Комментарии:
1. Не уверен, что вы хотите для
vec
…func(42)
иfunc("hello")
будет производить 2 разныхvec2
…2. Можем ли мы получить еще немного примеров того, что вы ищете? Начиная с C 17 с CTAD, вы можете использовать
std::vector vec{ initializers };
, и тип элемента вектора будет выведен для вас.3. Документ должен определить тип
ws
или тип.open
(откуда вы знаете, что можете позвонитьsubscribe(const char*)
?).4. На самом деле для этого проекта нет документа.
Ответ №1:
Проблема здесь в том, что auto
не имеет типа, пока он не будет использован, auto
сделайте его оператором вызова шаблона:
#include <iostream>
using namespace std;
int main()
{
auto func = [](auto param){
std::cout << param << std::endl;
};
func(4); // integer call
func("lol"); //const char* call
return 0;
}
Следствием этого является то, что param
может быть любой произвольный тип, прежде чем мы рассмотрим конкретное использование.
Если вы знаете аргумент, который будет предоставлен, то decltype
его можно применить:
#include <iostream>
using namespace std;
int main()
{
int arg1 = 4;
using Type1 = decltype(arg1); // type for the argument
auto func = [](auto param){
std::cout << param << std::endl;
};
func(arg1); // Type1 call
func("lol"); //const char* call
return 0;
}
Ответ №2:
Вы должны вручную просмотреть тип, который вы инициализируете.
Универсальный лямбда-код создает объект с шаблоном operator()
. Там мало что мешает быть несколькими экземплярами этого шаблона.
Если это так, то не существует типа, который является типом auto parameter
.
Вам относительно повезло здесь в том, что объект, который вы инициализируете всеми этими членами функтора, помещает аргументы прямо в его определение:
MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *)> open = nullptr;
Если вы не хотите снова просматривать определения, вы можете написать черту
template<typename Signature>
struct MoveOnlyFunctionTraits;
template <typename R, typename... Arguments>
struct MoveOnlyFunctionTraits<MoveOnlyFunctionTraits<R(Arguments...)> {
using result_type = R;
static constexpr auto arity = sizeof...(Arguments);
template <std::size_t I>
using argument = std::tuple_element_t<std::tuple<Arguments...>, I>;
}
template<typename Signature, std::size_t I>
using argument_t = typename MoveOnlyFunctionTraits<Signature>::template argument<I>;
Это позволяет вам вытащить тип
using websocket_type = argument_t<decltype(uWS::App::WebSocketBehaviour<DataType>::open), 0>;
std::vector<websocket_type> users;
Или вы можете отправить запрос на извлечение в библиотеку, которая предоставляет псевдонимы типов, которые вас интересуют
template <bool SSL>
struct TemplatedApp {
// existing members ...
public:
template <typename DataType>
using websocket_type = WebSocket<SSL, true, DataType>;
};
Затем
std::vector<uWS::App::template websocket_type<DataType> *> users;
Ответ №3:
Или, может быть, вы могли бы использовать шаблоны.
#include <vector>
template<typename type_t>
void some_function(const type_t value)
{
std::vector<type_t> vec;
auto func = [](const type_tamp; parameter)
{
std::vector<type_t> vec2;
};
//....
}
auto get_something()
{
// some made up complex data type returned as auto
using some_complex_data_type_from_somewhere_t = std::vector<std::vector<int>>;
some_complex_data_type_from_somewhere_t value{};
return value;
}
int main()
{
auto value = get_something();
some_function(value);
return 0;
}
Ответ №4:
Вы можете «загрузить» вывод типа в псевдоним типа.
void some_function() {
using value_type = decltype(infer_from_somewhere);
// alt: using value_type = typename some::annoyingly<complex>::type;
std::vector<value_type> vec;
auto func = [](value_type parameter){
std::vector<value_type> vec2;
};
//...
}
Комментарии:
1. Поскольку это фреймворк, параметр недоступен ни в одной точке основной функции или в глобальной области. Вот откуда берется главная проблема. Что мне нужно было сделать, так это проникнуть в исходный код и извлечь оттуда информацию о типе, чего я не хотел.
2. использование не ограничивается глобальным охватом. Вы также можете сделать это локально внутри функции
3. @nmd_07 В вашем вопросе говорится, что причина, по которой используется auto, заключается в том, что типы являются сложными и длинными, а не в том, что они полностью неопределимы, вам, вероятно, следует уточнить, что,
4. @Frank, вы можете объявить тип параметра lambda, посмотрев исходный код для этой конкретной функции, но все документы платформы вместо этого используют auto, так как объявление для этого типа действительно длинное.