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() { ? }
    

私の質問は 2 つあります。

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

2 番目のステップはスタイルの問題です。本当に重要なのは、最初のステップで最も効果的な作業ができるようにすることです。

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

ライブワークスペースにも。

これは私が実装することを選択した方法ではありませんが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 に答える