2016-09-23 1 views
2

テンプレートの引数として関数テンプレートの詳細を抽出しようとしています。余分なテンプレート引数が原因でオーバーロードのあいまいさが発生する

#include <tuple> 

template <typename T> 
struct Generator 
{ 
    typedef int type; 
    int operator()(int i) const { return i; } 
}; 

// old functions 
template < 
    typename... Args, 
    typename... FArgs> 
std::tuple<Args...> g(
    std::tuple<Args...> & a, 
    FArgs&&... fargs) 
{ 
    return std::make_tuple((Generator<Args>()(fargs...))...); 
} 

template < 
    typename Arg, 
    typename... FArgs> 
std::tuple<Arg> g(
    std::tuple<Arg> & a, 
    FArgs&&... fargs) 
{ 
    return std::make_tuple((Generator<Arg>()(std::forward<FArgs>(fargs)...))); 
} 

// new functions 
template < 
    template <typename T> class F, 
    typename... Args, 
    typename... FArgs> 
std::tuple<Args...> h(
    std::tuple<Args...> & a, 
    FArgs&&... fargs) 
{ 
    return std::make_tuple((F<Args>()(fargs...))...); 
} 

template < 
    template <typename> class F, 
    typename Arg, 
    typename... FArgs> 
std::tuple<Arg> h(
    std::tuple<Arg> & a, 
    FArgs&&... fargs) 
{ 
    return std::make_tuple((F<Arg>()(std::forward<FArgs>(fargs)...))); 
} 

int main() 
{ 
    auto t = std::make_tuple(1); 
    auto y = g(t, 2); 
    auto z = h<Generator>(t, 2); // ERROR 
} 

それは打ち鳴らすと罰金コンパイルが、私は次のエラーを取得するのgcc(4.9、5.3、および6.2)を使用して:

% g++ --std=c++11 test.cc 
test.cc: In function ‘int main()’: 
test.cc:56:28: error: call of overloaded ‘h(std::tuple<int>&, int)’ is ambiguous 
    auto z = h<Generator>(t, 2); 
          ^
test.cc:34:21: note: candidate: std::tuple<_Elements ...> h(std::tuple<_Elements ...>&, FArgs&& ...) [with F = Generator; Args = {int}; FArgs = {int}] 
std::tuple<Args...> h(
        ^
test.cc:45:17: note: candidate: std::tuple<Arg> h(std::tuple<Arg>&, FArgs&& ...) [with F = Generator; Arg = int; FArgs = {int}] 
std::tuple<Arg> h(

することは、これは曖昧べきか?もしそうなら、なぜgへの呼び出しもあいまいではありませんか?

+0

「Generator ()(fargs ...) 'と何かが足りない。 'Generator'の' operator() 'メンバ関数は常に一つのパラメータをとります。あなたはどのようにそれを10個のパラメータを含むパラメータパックとともに使用することを期待していますか? –

+0

@SamVarshavchikこれは私の実際のコードを削除したものです。 – pelletjl

答えて

0

と同じように、あなたの新しい関数を定義します。

template < 
    template <typename T> class F, 
    typename... Args, 
    typename... FArgs> 
std::enable_if_t<(sizeof...(Args)>1), std::tuple<Args...>> h(
    std::tuple<Args...> & a, 
    FArgs&&... fargs) 
{ 
    return std::make_tuple((F<Args>()(fargs...))...); 
} 

template < 
    template <typename> class F, 
    typename Arg, 
    typename... FArgs> 
std::tuple<Arg> h(
     std::tuple<Arg> & a, 
     FArgs&&... fargs) 
{ 
    return std::make_tuple((F<Arg>()(std::forward<FArgs>(fargs)...))); 
} 

これは明確にすることができますし、実際にあなたのコードがコンパイルされます。

は実際には、hの両方の実装は、一種類のみ、それらの両方に有効であるとtupleと、引数としてinttupleを取ります。
sfinae式(enable_if_tを参照)は、その場合はhの2番目の実装を選択しなければなりません。

+0

これを回避策として使用しました。私はそれがgccのバグかどうか、あるいは実際にはあいまいかどうかについて、より明確な答えが得られることを期待していました。 – pelletjl

+0

私は答えでそれを言った、それはGCCのバグではなく、実際にはあいまいでした。答えのコードは、それを明確にする方法を説明しています。それで全部です。 – skypjack

+1

これは本当ですが、gがあいまいではない理由を説明していません。 – pelletjl

関連する問題