使用自动 lambda 参数设置外部变量的类型

Setting type of an outer variable using auto lambda parameters

我正在使用大量使用回调 lambda 函数的 C++ Web 框架。正如您可能猜到的那样,lambda 的参数通常指定为 auto,因为必须声明很长的声明。

现在我使用 decltype() 运算符来查找由 auto 推导的正确类型,以便我可以声明相同类型的向量。当 vector 声明发生在 lambda 内部时,一切都很好。

我的问题开始于此向量需要使用 lambdas auto 参数的类型信息在外部范围内声明。下面是一个简单的例子:

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 & ws2 : users)
                if(ws != ws2)
                    ws2->send(message2, opCode);

        }catch(std::exception& e){
            std::cout << e.what() << std::endl;
        }
    },
});

现在,main.cpp 中的任何地方都需要将参数传递给 lambda 函数。这就是主要问题的来源。

您可以将类型推断“前端加载”到类型别名中。

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;
  };

  //...
}

或者您可以使用模板。

#include <vector>

template<typename type_t>
void some_function(const type_t value) 
{
    std::vector<type_t> vec;
    auto func = [](const type_t& 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;
}

这里的问题是 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;
}

您必须手动查看您正在初始化的类型。

通用 lambda 使用模板 operator() 创建对象。该模板的 多个 实例化并没有太多限制。

如果是这样,那么就没有 a 类型是 auto parameter.

的类型

你在这里相对幸运,因为你用所有这些仿函数成员初始化的对象将参数放在它的定义中:

MoveOnlyFunction<void(WebSocket<SSL, true, UserData> *)> open = nullptr;

如果不想再看定义,可以写一个trait

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;