簡體   English   中英

C ++ 17:使用泛型variadic lambda包裝可調用

[英]C++17: Wrapping callable using generic variadic lambda

我想在另一個callable中透明地包裝任何類型的可調用(例如lambda)以注入其他功能。 包裝器的類型應該與原始可調用的類型相同:

  • 相同的參數類型
  • 相同的退貨類型
  • 完美轉發傳遞的參數
  • 在SFINAE構造中使用時的行為相同

我試圖使用泛型variadic lambdas作為包裝:

#include <iostream>
#include <type_traits>

template<class TCallable>
auto wrap(TCallable&& callable) {
    return [callable = std::forward<TCallable>(callable)](auto&&... args) -> std::invoke_result_t<TCallable,decltype(args)...> {
        std::cout << "This is some additional functionality" << std::endl;
        return callable(std::forward<decltype(args)>(args)...);
    };
}

int main(int argc, char *argv[])
{
    auto callable1 = []() {
        std::cout << "test1" << std::endl;
    };

    auto callable2 = [](int arg) {
        std::cout << "test2: " << arg << std::endl;
    };

    auto wrapped1 = wrap(callable1);
    auto wrapped2 = wrap(callable2);

    static_assert(std::is_invocable_v<decltype(callable1)>); // OK
    static_assert(std::is_invocable_v<decltype(wrapped1)>); // fails
    static_assert(std::is_invocable_v<decltype(callable2), int>); // OK
    static_assert(std::is_invocable_v<decltype(wrapped2), int>); // fails
}

正如static_assert上的注釋所示,包裝器callables的調用方式與原始callable的調用方式不同。 需要改變什么才能實現所需的功能?

給出的示例是使用Visual Studio 2017(msvc 15.9.0)編譯的。

這可能是MSVC實現std::invoke_resultstd::is_invocable一個錯誤(即使使用Visual Studio 15.9.2,我也可以在這里重現這個問題)。 你的代碼使用clang(libc ++)和gcc工作正常,我沒有看到任何理由不應該這樣做。 但是,你真的不需要std::invoke_result ,你可以讓你的lambda推導出返回類型:

template<class TCallable>
auto wrap(TCallable&& callable) {
    return [callable = std::forward<TCallable>(callable)](auto&&... args) -> decltype(auto) {
        std::cout << "This is some additional functionality" << std::endl;
        return callable(std::forward<decltype(args)>(args)...);
    };
}

那么MSVC似乎也能正常工作 ......

編輯:正如Piotr Skotnicki在下面的評論中所指出的, decltype(auto)將禁止SFINAE 要解決此問題,您可以使用尾隨返回類型:

template<class TCallable>
auto wrap(TCallable&& callable) {
    return [callable = std::forward<TCallable>(callable)](auto&&... args) -> decltype(callable(std::forward<decltype(args)>(args)...)) {
        std::cout << "This is some additional functionality" << std::endl;
        return callable(std::forward<decltype(args)>(args)...);
    };
}

這將是一個更多的打字,但應該與SFINAE一起使用, 並且似乎也可以與MSVC一起使用 ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM