5

現在、私はいくつかのコードをさまざまなタイプに異なる方法で反応させようとしています。これは正確なコードではありませんが、メッセージは伝わります。

template<class A, class B>
struct alpha {
  enum { value = 0 };
};

template<class T, class... Args>
struct alpha<std::tuple<Args...>, T> {
  enum { value = 1 };
};

// This gets ignored
template<class T, class... Args>
struct alpha<std::tuple<Args..., std::vector<T> >, T> {
  enum { value = 2 };
};

// This gets ignored
template<class T, class... Args>
struct alpha<std::tuple<Args..., T>, T> {
  enum { value = 3 };
};

template<class T, class... Args>
struct alpha<T, std::tuple<Args...> > {
  enum { value = 4 };
};

template<class... LArgs, class... RArgs>
struct alpha<std::tuple<LArgs...>, std::tuple<RArgs...> > {
  enum { value = 5 };
};

int main(int argc, char* argv[]) {
  std::cout << alpha<std::tuple<int, double>, double>::value << std::endl; // prints 1
  return 0;
}

このコードが示す以上のことを試しましたが、これまでのところ何も機能せず、名前空間以外のスコープでの明示的な特殊化に関する問題に遭遇しました。参考までに、私は gcc 4.6 (oneiric サーバーに付属するもの) に取り組んでおり、可変個引数テンプレートを完全にサポートしていると思います。実装がパラメーター パックの最後の引数と他の型も検出するように機能する場合、それがどれほど醜くなるかは気にしません。助言がありますか?

編集:回答に基づいて使用したソリューションを共有したかった(これは一例です)。

template<typename T> struct tuple_last;

template<typename T, typename U, typename... Args>
struct tuple_last<std::tuple<T,U,Args...>> {
  typedef typename tuple_last<std::tuple<U,Args...>>::type type;
};

template<typename T>
struct tuple_last<std::tuple<T>> {
  typedef T type;
};

namespace details {
// default case:
template<class T, class U>
struct alpha_impl {
enum { value = 1 };
};

template<class T>
struct alpha_impl<T, T> {
enum { value = 101 };
};

template<class T>
struct alpha_impl<T, std::vector<T>> {
enum { value = 102 };
};

// and so on.
}

template<class T, class... Args>
struct alpha<std::tuple<Args...>, T>
  : details::alpha_impl<T, tuple_last<std::tuple<Args...>>;
4

3 に答える 3

13

clangを使用してコンパイルすると、(2) と (3) が使用できないことが報告されます。選ばれると予想される(3)の注意事項は以下の通りです。

警告: クラス テンプレートの部分的な特殊化には、推定できないテンプレート パラメーターが含まれています。この部分的な特殊化は決して使用されません

struct alpha<std::tuple<Args..., T>, T> {
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

注: 推測できないテンプレート パラメータ ' Args'

template<class T, class... Args>
                           ^

なぜArgs演繹できないのですか?C++0x FDIS は、§14.8.2.5/9 で次のように述べています。

[テンプレート パラメーターに関して指定された型] のテンプレート引数リストに、最後のテンプレート引数ではないパック展開が含まれている場合、テンプレート引数リスト全体が非推定コンテキストです。

あなたの専門分野では、型std::tuple<Args..., T>はテンプレート パラメーターArgsおよびに関して指定される型ですT。パック展開 ( Args...) が含まれていますが、そのパック展開は最後のテンプレート引数ではありません (Tは最後のテンプレート引数です)。したがって、 のテンプレート引数リストtuple全体 ( の全体<Args..., T>) は非推定コンテキストです。

の引数リストはstd::tuple、テンプレートの特殊化の引数リストにArgs表示される唯一の場所です。そこから推測できないため、まったく推測できず、特殊化は使用されません。

Matthieu M.は、回答で巧妙な回避策を提供しています

于 2011-07-20T06:28:01.900 に答える
12

@James が理由を提供してくれたので、代わりの方法を見つけてみましょう。

別のレベルの間接化を使用することをお勧めします。

1. 最後の引数の取得

template <typename T> struct Last;

template <typename T, typename U, typename... Args>
struct Last<std::tuple<T,U,Args...>>
{
  typedef typename Last<std::tuple<U,Args...>>::type type;
};

template <typename T>
struct Last<std::tuple<T>>
{
  typedef T type;
};

2.専門ヘルパーのご紹介

template <typename T, typename U>
struct alpha_tuple
{
  enum { value = 1 };
};

template <typename T>
struct alpha_tuple<T,T>
{
  enum { value = 3 };
};

template <typename T>
struct alpha_tuple<std::vector<T>,T>
{
  enum { value = 2; }
};

3.接続する

template <typename T>
struct alpha<std::tuple<>, T>
{
  enum { value = 1 };
};

template <typename T, typename U, typename Args...>
struct alpha<std::tuple<U, Args...>, T>
{
  typedef typename Last<std::tuple<U, Args...>>::type LastType;
  enum { value = alpha_tuple<LastType,T>::value };
};

空のタプルには最後の型がないことに注意してください。したがって、別の特殊化でそれらを処理する必要がありました。

于 2011-07-20T07:22:54.920 に答える
1

タプルが特定の最後のメンバーであるかどうかを調べたい場合は、そのための型特性を次に示します。

#include <type_traits>
#include <tuple>

template <typename ...Args> struct back;
template <typename T, typename ...Args> struct back<T, Args...>
  { typedef typename back<Args...>::type type; };
template <typename T> struct back<T>
  { typedef T type; };


template <typename...> struct tuple_has_last : public std::false_type {};
template <typename T, typename... Args> struct tuple_has_last<T, std::tuple<Args...>>
{
  static const bool value = std::is_same<typename back<Args...>::type, T>::value;
};

編集:ああ、Matthieu がまったく同じことを既に書いているとは思いませんでした。どうでも。

于 2011-07-20T19:38:33.550 に答える