vs2015の可変個引数テンプレートにオーバーロードされたメンバー関数が見つかりません

モーガン

私はこれを本質にまで煮詰めようとしました。タイプでインデックス付けされたオブジェクトの「リスト」を含む可変個引数テンプレートクラスFooがあります。この関数を使用してbar<U>()、そのタイプの要素を抽出します。可変個引数テンプレートとstd :: enable_ifを使用してこれを解決し、bar<U>()T == Uの場所のみを定義します。次に、「using」を使用して基本クラスのすべての「bar」関数を公開します。

#include <type_traits>

template<typename... Ts>
class Foo
{
public:
    void bar() {}
};

template<typename T, typename... Ts>
class Foo<T, Ts...> : public Foo<Ts...>
{
public:
    using Foo<Ts...>::bar;

    template<typename U>
    typename std::enable_if<std::is_same<U, T>::value, U >::type
        bar()
    {
        return mObj;
    }
private:
    T mObj;
};

template<typename T>
void bar2()
{
    Foo<int, float, double> list;
    list.bar<T>();
}

int main()
{
    bar2<float>();
    return 0;
}

これは、ClangとVisual Studio 2015を除いて、うまく機能します。MSVC19.0と19.10の両方を試したところ、次のエラーが発生しました。

Compiled with  /EHsc /nologo /W4 /c
main.cpp
main.cpp(30): error C2672: 'Foo<int,float,double>::bar': no matching overloaded function found
main.cpp(35): note: see reference to function template instantiation 'void bar2<float>(void)' being compiled
main.cpp(30): error C2770: invalid explicit template argument(s) for 'std::enable_if<std::is_same<U,T>::value,U>::type Foo<int,float,double>::bar(void)'
        with
        [
            T=int
        ]
main.cpp(18): note: see declaration of 'Foo<int,float,double>::bar'

少なくとも4.7から6.3の間のGCCは、これをうまくコンパイルします。これは、Visual Studio2015にないc ++ 11の一部の機能によるものかもしれないと最初に思いましたが、驚くべきことに、これは古いVisual Studio 2013(MSVC 18.0)では正常にコンパイルされます。Clangも失敗します。

だから私の質問は、これはこれらのコンパイラの欠点ですか、それとも私がここで行っている許可されていないことはありますか?

list.bar<int>()テストされたすべてのコンパイラでコンパイルされるようなハードコードされたタイプで「bar」を呼び出すと、

ジャスティンタイム-モニカを復活させる

enable_ifここで使用するには、whenの代替オプションを提供する必要がありますis_same<U, T>::value == false理想的には、これは、すべての基本クラスメンバーbarをusing宣言で公開することによって実行できます...

using Foo<Ts...>::template bar;

残念ながら、これは規格で禁止されており、これを修正しないことが決定されましたしたがって、別の方法でそれらを公開する必要があります。したがって、最も簡単な解決策はFoo<Ts...>::template bar()、次のようにのラッパーを作成することです。

template<typename T, typename... Ts>
class Foo<T, Ts...> : public Foo<Ts...>
{
public:
    // using Foo<Ts...>::template bar; // Sadly, this is forbidden.

    template<typename U>
    typename std::enable_if<std::is_same<U, T>::value, U >::type
        bar()
    {
        return mObj;
    }

    // Additional wrapper, to compensate for lack of valid syntax.
    template<typename U>
    typename std::enable_if<!std::is_same<U, T>::value, U >::type
        bar()
    {
        return Foo<Ts...>::template bar<U>();
    }

private:
    T mObj;
};

ただし、ラッパーは。をFoo<Ts...>::bar()返すため、を呼び出すことができないことに注意してくださいvoidUがパックのメンバーではない場合に使用することを目的とした一般的なケースであると仮定すると、これを修正する方法は2つあります。

  • 変更しFoo<Ts...>::bar()ます。

    template<typename... Ts>
    class Foo
    {
    public:
        template<typename T>
        T bar()
        {
            // Return an invalid value.
            return T{-1};
        }
    };
    
  • メンバーでないFoo<T, Ts...>::bar()場合に使用する、の3番目のバージョンを提供します。これはを返しますこのためには、特性を定義して、それがパックに含まれているかどうかを検出すると便利です。UT, Ts...Foo<Ts...>::bar()

    template<typename...>
    struct is_in_pack : std::false_type {};
    
    template<typename U, typename T1, typename... Ts>
    struct is_in_pack<U, T1, Ts...> :
        std::integral_constant<bool,
                               std::is_same<U, T1>::value ||
                               is_in_pack<U, Ts...>::value>
    {};
    

    次に、トレイトを使用する必要があります。

    template<typename T, typename... Ts>
    class Foo<T, Ts...> : public Foo<Ts...>
    {
    public:
        // using Foo<Ts...>::template bar; // Sadly, this is forbidden.
    
        template<typename U>
        typename std::enable_if<std::is_same<U, T>::value, U >::type
            bar()
        {
            return mObj;
        }
    
        // Additional wrapper, to compensate for lack of valid syntax.
        // U is a member of <T, Ts...>.
        template<typename U>
        typename std::enable_if<!std::is_same<U, T>::value &&
                                is_in_pack<U, T, Ts...>::value, U >::type
            bar()
        {
            return Foo<Ts...>::template bar<U>();
        }
    
        // Additional wrapper, to compensate for lack of valid syntax.
        // U isn't a member of <T, Ts...>.
        template<typename U>
        typename std::enable_if<!is_in_pack<U, T, Ts...>::value>::type
            bar()
        {
            return Foo<>::bar();
        }
    
    private:
        T mObj;
    };
    

これらのオプションのうち、現在のコードにより近いので、後者をお勧めします。

簡単なテスト
複雑なテスト

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

可変個引数テンプレート引数でオーバーロードされた関数

分類Dev

メンバー関数のオーバーロードのために可変個引数テンプレートクラスから型を抽出します

分類Dev

可変個引数のテンプレート化されたメソッドのオーバーロード

分類Dev

可変個引数テンプレート関数のオーバーロードされた関数へのあいまいな呼び出し

分類Dev

可変個引数テンプレート関数のオーバーロードが失敗する

分類Dev

MSVCバグ?制約された関数のオーバーロードされたメンバーが見つかりません

分類Dev

オーバーロードされたメンバー関数が見つかりません。クラスはヘッダーにあります

分類Dev

エラーC2511:オーバーロードされたメンバー関数がクラスに見つかりません

分類Dev

依存型によるc ++ 11可変個引数関数テンプレートのオーバーロードはあいまいですか?

分類Dev

可変個引数テンプレート関数をどのようにオーバーロードしますか?

分類Dev

可変個引数テンプレート関数をどのようにオーバーロードしますか?

分類Dev

c ++:可変個引数テンプレートと関数のオーバーロード

分類Dev

#defineが原因でVS2015でメンバー関数[c ++]定義が見つかりません

分類Dev

可変個引数関数と可変個引数テンプレートのオーバーロードルックアップ

分類Dev

VS2013で可変個引数テンプレートを使用する場合の「オーバーロードされた関数へのあいまいな呼び出し」

分類Dev

可変個引数テンプレート-再帰関数-最後の可変個引数メンバー

分類Dev

VS2015:可変個引数テンプレートの特殊化

分類Dev

オーバーロードされたメンバー関数を関数テンプレートに渡す

分類Dev

可変個引数テンプレートの継承における演算子のオーバーロード

分類Dev

オーバーロードされた関数のテンプレート引数を推測できませんでした

分類Dev

可変個引数テンプレート関数名のルックアップで特殊化が見つかりません

分類Dev

可変個引数テンプレート関数名のルックアップで特殊化が見つかりません

分類Dev

C ++には引数の可変個引数テンプレート関数はありません

分類Dev

std :: invoke VS2015で指定された一致するオーバーロードされた関数が見つかりませんエラーを呼び出します

分類Dev

インスタンスで呼び出されたときにテンプレートクラスのテンプレートメンバー関数が見つかりません

分類Dev

テンプレート引数に基づいて関数オーバーロードのセットを使用して可変個引数テンプレートクラスを構築しますか?

分類Dev

再帰的可変個引数テンプレート関数-あいまいさはありませんか?

分類Dev

ostreamでstd :: endlを使用する '<<'-バリアントメンバーを含む可変個引数テンプレートクラスでの演算子のオーバーロードにより、コンパイラエラーが発生する

分類Dev

型消去と可変個引数テンプレートメンバー関数

Related 関連記事

  1. 1

    可変個引数テンプレート引数でオーバーロードされた関数

  2. 2

    メンバー関数のオーバーロードのために可変個引数テンプレートクラスから型を抽出します

  3. 3

    可変個引数のテンプレート化されたメソッドのオーバーロード

  4. 4

    可変個引数テンプレート関数のオーバーロードされた関数へのあいまいな呼び出し

  5. 5

    可変個引数テンプレート関数のオーバーロードが失敗する

  6. 6

    MSVCバグ?制約された関数のオーバーロードされたメンバーが見つかりません

  7. 7

    オーバーロードされたメンバー関数が見つかりません。クラスはヘッダーにあります

  8. 8

    エラーC2511:オーバーロードされたメンバー関数がクラスに見つかりません

  9. 9

    依存型によるc ++ 11可変個引数関数テンプレートのオーバーロードはあいまいですか?

  10. 10

    可変個引数テンプレート関数をどのようにオーバーロードしますか?

  11. 11

    可変個引数テンプレート関数をどのようにオーバーロードしますか?

  12. 12

    c ++:可変個引数テンプレートと関数のオーバーロード

  13. 13

    #defineが原因でVS2015でメンバー関数[c ++]定義が見つかりません

  14. 14

    可変個引数関数と可変個引数テンプレートのオーバーロードルックアップ

  15. 15

    VS2013で可変個引数テンプレートを使用する場合の「オーバーロードされた関数へのあいまいな呼び出し」

  16. 16

    可変個引数テンプレート-再帰関数-最後の可変個引数メンバー

  17. 17

    VS2015:可変個引数テンプレートの特殊化

  18. 18

    オーバーロードされたメンバー関数を関数テンプレートに渡す

  19. 19

    可変個引数テンプレートの継承における演算子のオーバーロード

  20. 20

    オーバーロードされた関数のテンプレート引数を推測できませんでした

  21. 21

    可変個引数テンプレート関数名のルックアップで特殊化が見つかりません

  22. 22

    可変個引数テンプレート関数名のルックアップで特殊化が見つかりません

  23. 23

    C ++には引数の可変個引数テンプレート関数はありません

  24. 24

    std :: invoke VS2015で指定された一致するオーバーロードされた関数が見つかりませんエラーを呼び出します

  25. 25

    インスタンスで呼び出されたときにテンプレートクラスのテンプレートメンバー関数が見つかりません

  26. 26

    テンプレート引数に基づいて関数オーバーロードのセットを使用して可変個引数テンプレートクラスを構築しますか?

  27. 27

    再帰的可変個引数テンプレート関数-あいまいさはありませんか?

  28. 28

    ostreamでstd :: endlを使用する '<<'-バリアントメンバーを含む可変個引数テンプレートクラスでの演算子のオーバーロードにより、コンパイラエラーが発生する

  29. 29

    型消去と可変個引数テンプレートメンバー関数

ホットタグ

アーカイブ