23500


以下のC++11のコードについて

[code]

    #include <iostream>
    #include <tuple>
    #include <utility>
    #include <cxxabi.h>
    #include <typeinfo>
    
    class foo
    {
    public:
        template<typename... types_>
        void method1(types_&&... args) {
            int status;
    
            auto method2_args = std::make_tuple(
                    std::forward<types_>(args)...
            );
            auto fp = &foo::method2<int, int, decltype(method2_args)>;
            std::cout << abi::__cxa_demangle(typeid(method2_args).name(), 0, 0, &status) << std::endl;
            std::cout << abi::__cxa_demangle(typeid(fp).name(), 0, 0, &status) << std::endl;
    //      (this ->*fp)(1, 2, method2_args); // error: invalid initialization of reference of type ‘std::tuple<int, int, std::tuple<float, double> >&’ from expression of type ‘std::tuple<float, double>’
        }
    
        template<typename... types_>
        void method2(int a, int b, std::tuple<types_...> &args )
        {
        }
    };
    
    int main()
    {
        foo f;
        f.method1(1.0f, 2.0);
    }
    
[/code]

(this ->*fp)(1, 2, method2_args);がエラーとなってコンパイルできません。  
コンパイラはg++-4.8です。g++-5.0, clang++-3.4でもエラーでした。

不思議に思い、エラー箇所をコメントアウトして、method2_argsとfpのtype_info::name()を表示させたところ

[code]

    std::tuple&ltfloat;, double>
    void (foo::*)(int, int, std::tuple&ltint;, int, std::tuple&ltfloat;, double> >&)
    
[/code]

でした。最初のがmethod2_argsで次がfpのtype_info::name()です。  
method2_argsは期待どおりでした。  
しかしfpは実に奇妙で期待していたものと違いました。

[code]

    void (foo::*)(int, int, std::tuple&ltfloat;, double> >&)
    
[/code]

を期待していました。

  * 質問１．  
fpはなぜこのような結果になるのでしょうか？

  * 質問２．  
fpを私が期待したものにするにはどうしたらよいでしょうか？


CC BY-SA 3.0
2016-03-26T08:05:55.453
23480
2016-03-27T06:21:32.927
7844
question
c++ c++11
可変長引数テンプレートメンバ関数へのポインタ。その引数が期待通りにならない。


_fpはなぜこのような結果になるのでしょうか？_

  * method2の引数`int a, int b,`は、型パラメータ`types_`を使用していませんから`auto fp = &foo::method2<int, int, decltype(method2_args)>;`のようにそれらに対応する`int, int,`を実型引数に与えてはいけません。
  * `method2_args`のデータ型はすでに`std::tuple<float, double>`なのですから、そのデータ型を(method2の)`types_`に渡せば`std::tuple<types_...>`は当然tupleのtupleになります。

_fpを私が期待したものにするにはどうしたらよいでしょうか？_  
gccは手元にないので、Clangで確認しただけですが、次のように`fp`だけでなく`method2`も書き換える必要があるでしょう。

[code]

        template<typename... types_>
        void method1(types_&&... args) {
            int status;
    
            auto method2_args = std::make_tuple(
                std::forward<types_>(args)...
            );
            auto fp = &foo::method2<decltype(method2_args)>;
            std::cout << abi::__cxa_demangle(typeid(method2_args).name(), 0, 0, &status) << std::endl;
            std::cout << abi::__cxa_demangle(typeid(fp).name(), 0, 0, &status) << std::endl;
            (this ->*fp)(1, 2, method2_args);
        }
    
        template<typename arg_type>
        void method2(int a, int b, arg_type &args )
        {
        }
    
[/code]

(追記)  
`method2_args`の作り方を間違えると型の不整合が起こりますが、こうすればmethod2の書き換えは不要になりますね。

[code]

            auto fp = &foo::method2<types_...>;
    
[/code]

(他は質問者さんのコードのまま。)


CC BY-SA 3.0
2016-03-26T08:40:02.673
23482
2016-03-26T09:02:29.480
2016-03-26T09:02:29.480
13972
13972
23480
answer


自己回答です。  
fpを

[code]

    void (foo::*fp)(int, int, decltype(method2_args)&) = &foo::method2;
    
[/code]

とすることで、期待通りになりました。


CC BY-SA 3.0
2016-03-27T06:21:32.927
23500
2016-03-27T06:21:32.927
7844
23480
answer