2

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

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

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

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 函数。这就是主要问题的来源。

4

4 回答 4

2

这里的问题是在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;
}
于 2021-09-27T13:53:09.510 回答
1

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

通用 lambda 使用模板创建对象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;
于 2021-09-28T11:29:31.570 回答
1

或者,也许您可​​以使用模板。

#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;
}
于 2021-09-27T13:51:34.757 回答
0

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

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

  //...
}
于 2021-09-27T13:42:16.133 回答