簡體   English   中英

將可變參數模板參數與lambda相結合

[英]Combine variadic template arguments with a lambda

我知道現代C ++中的可變參數模板是什么,但是我無法繞過它以便能夠編寫如下代碼:

#include <iostream>
#include <sstream>
using namespace std;


template <typename... Args, typename Combinator>
auto combine(Args... args, Combinator combinator)
{
    auto current_value = combinator(args...);
    return current_value;
}

int main() {
    auto comb = combine(1, "asdf"s, 14.2,
                [](const auto& a, const auto& b, const auto& c) { 
                    stringstream ss;
                    ss << a << "\n";
                    ss << b << "\n";
                    ss << c << "\n";
                    return ss.str();
                });

    return 0;
}

換句話說,我想給函數提供一個未知數量的不同類型的參數,但最后一個參數是lambda或用於以某種方式組合參數的任何可調用對象。 這個例子看起來純粹是學術性的,但在這個例子的基礎上,我想構建更多時髦的代碼,但首先我需要這個來編譯。 希望你能幫忙!

我無法編譯。 我不知道我錯過了什么。

以下是GCC吐口水:

In function 'int main()':
21:6: error: no matching function for call to 'combine(int, std::basic_string<char>, double, main()::<lambda(auto:1&, auto:2&, auto:3&)>)'
21:6: note: candidate is:
7:6: note: template<class ... Args, class Combinator> auto combine(Args ..., Combinator&&)
7:6: note: template argument deduction/substitution failed:
21:6: note: candidate expects 1 argument, 4 provided

可變參數模板必須是最后一個參數,因此可以推導出它,參見模板參數推導

非推斷的上下文

7)參數P是參數包,並不出現在參數列表的末尾:

 template<class... Ts, class T> void f1(T n, Ts... args); template<class... Ts, class T> void f2(Ts... args, T n); f1(1, 2, 3, 4); // P1 = T, A1 = 1: deduced T = int // P2 = Ts..., A2 = 2, A3 = 3, A4 = 4: deduced Ts = [int, int, int] f2(1, 2, 3, 4); // P1 = Ts...: Ts is non-deduced context 

您應該將其更改為:

#include <iostream>
#include <sstream>
using namespace std;


template <typename... Args, typename Combinator>
auto combine(Combinator combinator, Args&&... args)
{
    auto current_value = combinator(std::forward<Args>(args)...);
    return current_value;
}

int main() {
    auto comb = combine([](const auto& a, const auto& b, const auto& c) { 
                    stringstream ss;
                    ss << a << "\n";
                    ss << b << "\n";
                    ss << c << "\n";
                    return ss.str();
                },
                1, "asdf"s, 14.2);
    std::cout << comb;
    return 0;
}

換句話說,我想給函數提供一個未知數量的不同類型的參數,但最后一個參數是lambda或用於以某種方式組合參數的任何可調用對象。

由於傳遞callable作為最后一個參數似乎是你的問題的關鍵,這里有一種方法:

namespace detail {
    template<typename TupT, std::size_t... Is>
    auto combine(TupT&& tup, std::index_sequence<Is...>) {
        return std::get<sizeof...(Is)>(tup)(std::get<Is>(std::forward<TupT>(tup))...);
//             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^  last element in tuple is the callable
    }
}

template<typename... Ts>
auto combine(Ts&&... ts) {
    return detail::combine(
        std::forward_as_tuple(std::forward<Ts>(ts)...),
        std::make_index_sequence<sizeof...(Ts) - 1>{}
//                               ^^^^^^^^^^^^^^^^^  arg count = size of pack - 1 (callable)
    );
}

在線演示

這也實現了完美的轉發,這在你的問題的實現中是遺漏的。

您的代碼確實無法編譯,因為只有當變量模板參數是最后一個參數時才能推斷它們。

要在不更改界面的情況下執行此操作,您可以執行以下操作:

#include <iostream>
#include <sstream>

using namespace std;

template <typename... Args, typename Combinator>
auto combine_impl(Args... args, Combinator combinator) {
    return combinator(args...);
}

template <typename... Args>
auto combine(Args... args) {
    return combinator_impl<Args...>(args...);
}

int main() {
    auto comb = combine(1, "asdf"s, 14.2,
        [](const auto& a, const auto& b, const auto& c) {
            stringstream ss; ss << a << "\n"; ss << b << "\n"; ss << c << "\n";
            return ss.str();
        }
    );

    return 0;
}

但坦率地說,如果只是這樣做:

auto comb = [](const auto& a, const auto& b, const auto& c) {
    stringstream ss; ss << a << "\n"; ss << b << "\n"; ss << c << "\n";
    return ss.str();
}(1, "asdf"s, 14.2);

如果你不能在同一行上調用並聲明一個lambda,你可以使用C ++ 17的std::invoke

auto comb = std::invoke([](const auto& a, const auto& b, const auto& c) {
    stringstream ss; ss << a << "\n"; ss << b << "\n"; ss << c << "\n";
    return ss.str();
}, 1, "asdf"s, 14.2);

請注意,最后兩個版本比第一個解決方案更快,因為它們保留了值類型。

暫無
暫無

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

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