2017-11-04 9 views
6

バリデーションテンプレートで非常に奇妙な問題が発生しました。間違ったパックが展開されているようです。ここでは、コードスニペットです:バリデーションテンプレートで間違ったパックが展開されました

#include <tuple> 

template<typename...> 
struct types {}; 

template<typename = types<>> 
struct Base; 

template<typename... Args1> 
struct Base<types<Args1...>> { 
    template<typename... Args2> 
    static auto construct(Args1... args1, Args2&&... args2) 
     -> decltype(std::make_tuple(args1.forward()..., std::declval<Args2>()...)) 
    { 
     return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...); 
    } 
}; 

struct Derived : Base<> {}; 

int main() { 
    auto test = &Derived::construct<char const(&)[7]>; 
} 

私はこのエラーを取得する:

13 : <source>:13:43: error: request for member 'forward' in 'args2#0', which is of non-class type 'const char [7]' 
     -> decltype(std::make_tuple(args1.forward()..., std::declval<Args2>()...)) 
            ~~~~~~^~~~~~~ 
13 : <source>:13:43: error: request for member 'forward' in 'args2#0', which is of non-class type 'const char [7]' 
<source>: In function 'int main()': 
22 : <source>:22:27: error: unable to deduce 'auto' from '& construct<const char (&)[7]>' 
    auto test = &Derived::construct<char const(&)[7]>; 
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~ 
22 : <source>:22:27: note: could not resolve address from overloaded function '& construct<const char (&)[7]>' 
Compiler exited with result code 1 

パックはそれに値を持っているときしかし、それは起こりません。

struct HasForward { int forward() { return 0; } }; 

struct Derived : Base<types<HasForward>> {}; 

はここFirst snippet liveですおよびSecond snippet live

このコードで何が問題になっていますか?これはコンパイラのバグですか?それを克服し、最初のパックを空のままにする方法はありますか?

+0

マイ打ち鳴らす++問題なくコンパイル。私はそれがg ++バグだと思う。 – max66

答えて

3

Is this a compiler bug? Is there any ways to overcome it and leave the first pack empty?

コンパイラのバグのようです。

template<typename... Args1> 
class Base<types<Args1...>> { 
    template<typename... T, typename... U> 
    static auto ret(types<T...>, types<U...>) 
    -> decltype(std::make_tuple(std::declval<T>().forward()..., std::declval<U>()...)); 

public: 
    template<typename... Args2> 
    static auto construct(Args1... args1, Args2&&... args2) 
    -> decltype(ret(types<Args1...>{}, types<Args2...>{})) 
    { 
     return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...); 
    } 
}; 

ビット醜いが、it worksあなたの最初のパックは次のとおりです。
はあなたのパラメータをテストするには、次の例のような関数宣言(不要な定義)を使用して、それを使用することができ、それを回避するために、空の場合(C++ 11の場合も同様です)、リンカによってすべてが破棄されます。

--- EDIT @ W.Fによって示唆されるように

。コメント(提案のおかげで、私はそれに気付かなかった)で、それを達成することはさらに簡単です。
それは次のようにちょうどあなたの関数を定義:

static auto construct(Args1... args1, Args2&&... args2) 
    -> decltype(std::make_tuple(std::declval<Args1>().forward()..., std::declval<Args2>()...)) 
{ 
    return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...); 
} 
+0

ももっと簡単かもしれません。 'std :: declval ().forward()...'はうまくいくようです。 OPsコードを不正な形にするために心の実験を試みたが失敗した: –

+0

@ W.F。いい視点ね。私はそれに気付かなかった。回答を統合するためにあなたの提案を使うことはできますか? – skypjack

+1

どうぞよろしく!... –

関連する問題