【问题标题】:Computing a function over variadic templates在可变参数模板上计算函数
【发布时间】:2012-10-26 02:52:16
【问题描述】:

我试图找出在可变参数类型列表上实现函数的最惯用方式。例如,计算所有类型的最大大小。我知道有几种方法可以完成这样的任务,但我想知道何时选择哪种策略。

这些是我会考虑的机制(可能还有更多,如果有,请提及):

  • 类型特征(最好使用 using 声明简洁):

    template <typename Head>
    using max_size = typename std::integral_constant<size_t, sizeof(Head)>::type;
    
    template <typename Head, typename... Tail>
    using max_size = ?;
    
  • constexpr函数:

    template <typename Head>
    constexpr size_t max_size() { return sizeof(Head); }
    
    template <typename Head, typename... Tail>
    constexpr size_t max_size() { ? }
    

我的问题有两个:

  1. 计算的哪些特征决定了选择什么策略?

  2. 在每种情况下,上述最大尺寸示例的示例实现是什么样的?

【问题讨论】:

    标签: c++ c++11 variadic-templates variadic-functions constexpr


    【解决方案1】:

    我个人更喜欢函数而不是特征,我发现它们更易于操作且更自然。但这当然是主观的;)

    #include <iostream>
    
    template <typename Head>
    constexpr size_t max_size() { return sizeof(Head); }
    
    template <typename Head, typename Next, typename... Tail>
    constexpr size_t max_size() {
        return max_size<Head>() > max_size<Next, Tail...>() ?
               max_size<Head>() : max_size<Next, Tail...>();
    }
    
    int main() {
      std::cout << "int: " << max_size<int>() << "\n";
      std::cout << "char, short, int: " << max_size<char, short, int>() << "\n";
      std::cout << "char, double, int: " << max_size<char, double, int>() << "\n";
    }
    

    liveworkspace行动中:

    int: 4
    char, short, int: 4
    char, double, int: 8
    

    【讨论】:

    • 这是可用答案中最短、最清晰的解决方案。另一个优点是它不依赖于 Boost。
    • @MatthiasVallentin:是的,我倾向于转向constexpr,因为它们所以比元编程技巧更具可读性。更少的样板,更多的阅读函数的习惯。
    【解决方案2】:

    我不会严格使用constexpr,因为它们更难编写。例如,我什至不确定constexpr 是否可以使用高阶元函数,如果是这样,它们使用函数指针作为模板参数,这很丑。

    一般来说,我从一个元函数类开始:

    struct max_size {
      template<typename... Ts>
      struct apply : parampack_foldl::apply<boost::mpl::quote2<boost::mpl::max>, typename boost::mpl::sizeof_<Ts>::type...>;
    };
    

    然后创建一个别名来减少打字:

    template<typename... Ts>
    using MaxSize = typename max_size::apply<Ts>::type;
    

    或者,创建一个 constexpr 函数:

    template <typename... Ts>
    constexpr size_t max_size() { return max_size::apply<Ts...>::type::value; }
    

    第二步真的只是风格问题,真正重要的是你有第一个,它给你最多的工作。

    【讨论】:

    • 我喜欢高阶元函数的想法。它将允许编写单个 max 函数并传入另一个元函数来计算大小。它实际上似乎与 constexpr 函数一起工作得很好:liveworkspace.org/code/5809994d109ad35a1b68d2beb81b3ddd(链接指向 Matthieu 的示例,稍作修改。)
    【解决方案3】:

    为了完整性,还有继承的技术:

    #include <cstddef>
    using std::size_t;
    
    template<size_t ...S> struct max_size_t;
    
    template<size_t S1, size_t S2, size_t ...Rest>
    struct max_size_t<S1, S2, Rest...>
       : max_size_t<(S2 < S1) ? S1 : S2, Rest...> {
    };
    
    template<size_t S>
    struct max_size_t<S> {
      static const int value = S;
    }; 
    
    template<> struct max_size_t<> {
      static const int value = 0;
    };
    
    template<typename ...T> struct max_size : max_size_t<sizeof(T)...> {};
    
    // Using the same test-harness as Matthieu M:
    #include <iostream>
    
    int main() {
      std::cout << "int: " << max_size<int>::value << "\n";
      std::cout << "char, short, int: " << max_size<char, short, int>::value << "\n";
      std::cout << "char, double, int: " << max_size<char, double, int>::value << "\n";
      return 0;
    }
    

    同样在liveworkspace

    虽然这不是我选择实现max_size 的方式,但当所需的函数是返回类型的函数时,它非常方便(下面是高度人为的示例):

    template<typename T1, typename T2, bool B=(sizeof(T1)>sizeof(T2))> struct selector;
    template<typename T1, typename T2> struct selector<T1, T2, true> { using type = T1; };
    template<typename T1, typename T2> struct selector<T1, T2, false> { using type = T2; };
    
    template<typename T1, typename ...Rest> struct largest_type;
    
    template<typename T1, typename T2, typename ...Rest>
    struct largest_type<T1, T2, Rest...>
       : largest_type<typename selector<T1, T2>::type, Rest...> {};
    
    template<typename T1> struct largest_type<T1> { using type = T1; };
    
    #include <iostream>
    int main() {
      static const unsigned long long u = 1ULL << 63;
      std::cout << "int: " << typename largest_type<int>::type(u) << "\n";
      std::cout << "int, double: " << typename largest_type<int, double>::type(u) << "\n";
      std::cout << "short, float, long long: " << typename largest_type<short, float, long long>::type(u) << "\n";
    return 0;
    }
    

    here

    【讨论】:

      猜你喜欢
      • 2011-08-26
      • 1970-01-01
      • 1970-01-01
      • 2021-10-01
      • 2016-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多