2011-07-20 14 views
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(1つのサーバに付属しているもの)に取り組んでいます。これは、完全な可変的なテンプレートサポートを持っていると思います。私は実装がパラメータパックの最後の引数と他の型を検出するように働くならば、それがどれほど醜いか気にしない。助言がありますか?

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

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

答えて

13

あなたがclangを使用してコンパイルした場合、それは親切(2)と(3)が使用不可能であることを報告します。

警告:クラステンプレートには、推測できないテンプレートパラメータが含まれています。非推論テンプレートパラメータ 'Args'

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

なぜ推論ではないArgsです:?この部分的な特殊化は、ノート

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

を使用されることはありませんか§14.8.2.5/ 9のC++ 0x FDISの状態:

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

、タイプstd::tuple<Args..., T>は、テンプレートパラメータArgsTの面で指定されているタイプです。パック展開(Args...)が含まれていますが、パック展開は最後のテンプレート引数ではありません(Tが最後のテンプレート引数です)。したがって、tuple(全体は<Args..., T>)のテンプレート引数リスト全体は、推論されないコンテキストです。

std::tupleの引数リストは、テンプレート特殊化の引数リスト内の唯一の場所であり、Argsが表示されます。そこから推論できないので、それは全く推論できず、専門化は決して使用されません。

Matthieu M. provides a clever workaround in his answer

+0

私は "解決策"が何であるか、まったく何があるか分かりません。しかし、ここに知っている人がいます。 –

+0

少なくとも、この方法を使用する可能性のある解決法はありませんし、私は他の人に移ります。私が好きなものを思いついたら、それを投稿します。 – norcalli

+0

これが問題だとすれば、左側のパックを展開してみませんか? – dascandy

12

@Jamesは理由を提供しましたが、代わりに見つけようとしています。

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

1。最後の引数に空のための最後のタイプが存在しないことに注意

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 }; 
}; 
を、それをフック

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 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を取得私は別の専門分野でそれらを扱わなければなりませんでした。

+0

面白い、私はまさに似たようなことをして、最後の議論をしようとしていました。どうすれば正しい答えが得られますか?私は新しいstackoverflowです。 – norcalli

+0

@Norcalli:それは不可能です。どちらか一方を選択する必要があります。私はあなたが遭遇した問題(より一般的です)を説明して以来、ジェームズを選択したままにしておくことをお勧めします。私の答えはあなたのユースケースに合わせて調整されているため、将来の読者にはあまり関心がありません。 –

+0

非常にいい...... –

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

編集:ああ、私はマシューが既に書かれていたことがわかりませんでしたまったく同じこと。気にしないで。

関連する問題