代码之家  ›  专栏  ›  技术社区  ›  Bérenger

将模板函数转换为通用lambda

  •  6
  • Bérenger  · 技术社区  · 7 年前

    #include <iostream>
    #include <vector>
    #include <tuple>
    #include <string>
    #include <utility> 
    
    
    // for_each with std::tuple
    // (from https://stackoverflow.com/a/6894436/1583122)
    template<std::size_t I = 0, typename FuncT, typename... Tp>
    inline typename std::enable_if<I == sizeof...(Tp), void>::type
    for_each(std::tuple<Tp...> &, FuncT)
    {}
    
    template<std::size_t I = 0, typename FuncT, typename... Tp>
    inline typename std::enable_if<I < sizeof...(Tp), void>::type
    for_each(std::tuple<Tp...>& t, FuncT f) {
        f(std::get<I>(t));
        for_each<I + 1, FuncT, Tp...>(t, f);
    }
    
    // my code
    template<class T> auto
    print(const std::vector<T>& v) -> void {
        for (const auto& e : v) {
            std::cout << e << "\t";
        }
    }
    
    struct print_wrapper {
        template<class T>
        auto operator()(const std::vector<T>& v) {
            print(v);
        }
    };
    
    auto print_gen_lambda = [](const auto& v){ print(v); };
    
    auto print_gen_lambda_2 = []<class T>(const std::vector<T>& v){ print(v); }; // proposal P0428R1, gcc extension in c++14/c++17
    
    int main() {
         std::tuple<std::vector<int>,std::vector<double>,std::vector<std::string>> t = { {42,43},{3.14,2.7},{"Hello","World"}};
        for_each(t, print); // case 1: error: template argument deduction/substitution failed: couldn't deduce template parameter 'FuncT'
        for_each(t, print_wrapper()); // case 2: ok
        for_each(t, print_gen_lambda); // case 3: ok
        for_each(t, print_gen_lambda_2); // case 4: ok
    }
    

    注意,情况2和4严格等效。案例3更一般,但不受约束(这对我来说是个问题)。我认为案例1应该被语言等同于案例2和4,然而事实并非如此。

    • 是否有建议将模板函数隐式转换为通用约束lambda(案例2/4)?如果没有,是否有根本的语言原因阻止这样做?
    • 到目前为止,我必须使用案例2,这相当麻烦。
      • c++20
      • 案例3:不受约束,但我依赖(此处未显示)替换失败来调用带有非“向量”参数的“print”(P0428R1提到了这个问题)。所以我想次要的问题是“我能用一些enable\u if技巧约束一个通用lambda吗?”

    2 回复  |  直到 7 年前
        1
  •  9
  •   Vittorio Romeo    7 年前

    在C++14/17/20中,是否有一种非常简洁的方式来实现从案例1到案例2的转换?我甚至对宏黑客持开放态度。

    // C++ requires you to type out the same function body three times to obtain
    // SFINAE-friendliness and noexcept-correctness. That's unacceptable.
    #define RETURNS(...) noexcept(noexcept(__VA_ARGS__)) \
         -> decltype(__VA_ARGS__){ return __VA_ARGS__; }
    
    // The name of overload sets can be legally used as part of a function call -
    // we can use a macro to create a lambda for us that "lifts" the overload set
    // into a function object.
    #define LIFT(f) [](auto&&... xs) RETURNS(f(::std::forward<decltype(xs)>(xs)...))
    

    然后你可以说:

    for_each(t, LIFT(print)); 
    

    是的,看 P0119 N3617

        2
  •  3
  •   skypjack    7 年前

    我可以用一些enable\U if技巧约束通用lambda吗?

    static_assert C-ish公司

    下面是一个最小的工作示例:

    #include<vector>
    #include<type_traits>
    #include<utility>
    #include<list>
    
    template<template<typename...> class C, typename... A>
    constexpr std::true_type spec(int, C<A...>);
    
    template<template<typename...> class C, template<typename...> class T, typename... A>
    constexpr std::false_type spec(char, T<A...>);
    
    int main() {
        auto fn = [](auto&& v) {
            static_assert(decltype(spec<std::vector>(0, std::declval<std::decay_t<decltype(v)>>()))::value, "!");
            // ...
        };
    
        fn(std::vector<int>{});
        // fn(std::list<int>{});
        //fn(int{});
    }
    

    如果将注释切换到最后一行,则
    wandbox .


    旁注。

    static_assert(decltype(spec<std::vector>(0, std::declval<std::decay_t<decltype(v)>>()))::value, "!");
    

    添加如下所示的变量模板:

    template<template<typename...> class C, typename T>
    constexpr bool match = decltype(spec<C>(0, std::declval<std::decay_t<T>>()))::value;
    

    然后在你的 s:

    static_assert(match<std::vector, decltype(v)>, "!");
    


    笔记

    在C++17中,通过将lambda定义为:

    auto fn = [](auto&& v) {
        if constexpr(match<std::vector, decltype(v)>) {
            print(v);
        }
    };
    

    wandbox .