3

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

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

  • 类型特征(最好使用 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. 在每种情况下,上述最大尺寸示例的示例实现如何?

4

3 回答 3

5

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

#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
于 2012-11-06T07:34:44.147 回答
3

我会远离严格使用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; }

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

于 2012-11-06T07:44:35.550 回答
1

为了完整起见,还有继承技术:

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

在这里看到它。

于 2012-11-06T17:49:49.880 回答