71286


以下はC#のコードです。  
C++でaと等価な型は定義できるでしょうか？

[code]

    using System;
    
    namespace ConsoleApp1
    {
        class Program
        {
            delegate a a();
    
            static void Main(string[] args)
            {
                a x = f;
                for (int i = 0; i < 10; ++i) x = x();
            }
            static a f() { Console.Write("f"); return g; }
            static a g() { Console.Write("g"); return f; }
        }
    }
    
[/code]

C++で関数ポインタを使い、実装したかなり近いコードが以下になりますが、  
キャストが必須で、可能ならばキャストをなくしたいです。

[code]

    #include <stdio.h>
    typedef void *(*a)();
    void *f();
    void *g();
        
    void *f() { puts("f"); return (void *)g; }
    void *g() { puts("g"); return (void *)f; }
    
    int main()
    {
        a x = f;
        for (int i = 0; i < 10; ++i)x = (a)x();
        return 0;
    }
    
[/code]

私はC++では完全にキャストなしのaを定義できないのではないか？と疑っています。  
aのポイントは関数の戻り値の型がその関数自身になっているところです。  
C++でリストのクラスを作るとき

[code]

    class Node
    {
    public:
        Item item;
        Node *nxt;
    };
    
[/code]

のような自分自身のポインタを定義に含めるような書き方をできると思うのですが、  
今回のaのような関数と戻り値の場合、そのような書き方が用意されていないように思えるのです。

今回の質問の元ネタは5chの「なあ、再帰関数好きな人いる？ パート3」というスレの>>676になります。  
<https://mevius.5ch.net/test/read.cgi/tech/1448704298/>


CC BY-SA 4.0
2020-10-16T23:26:18.503
71264
2020-10-17T15:39:01.767
2020-10-17T04:25:15.763
18637
18637
question
c# c++
この型をC++で定義できますか？


C# のデリゲートは[概要](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-
guide/delegates/#delegates-overview)を読むのが早いでしょう。

>   * デリゲートは C++ 関数ポインターと似ていますが、デリゲートは完全なオブジェクト指向です。また、メンバー関数への C++
> ポインターとは異なり、デリゲートではオブジェクト インスタンスとメソッドの両方をカプセル化します。
>

ということで、機能は２つあり、

  * 関数ポインター
  * メンバー関数ポインター＋対象オブジェクトのペア

となっています。  
今回の例に関して言えば、 `g` や `f` は静的メソッド（C++言語における静的メンバー関数）なので、C++言語では関数ポインターで表せます。


CC BY-SA 4.0
2020-10-17T02:40:26.350
71269
2020-10-17T02:40:26.350
4236
71264
answer


関数オブジェクトを使えばキャストせずに同様の形式で書けることは書けますね。

[code]

    #include <iostream>
    
    class Program {
        class A {
        public:
            virtual A *func() {
                static A a;
                return &a;
            }
            A *operator()() {
                return func();
            }
        };
        class F : public A {
        public:
            A *func() override {
                std::cout << "f";
                static G g;
                return &g;
            }
        };
        class G : public A {
        public:
            A *func() override {
                std::cout << "g";
                static F f;
                return &f;
            }
        };
    public:
        static void exec() {
            F f;
            A *x = &f;
            for (int i = 0; i < 10; ++i) x = (*x)();
        }
    };
    
    int main()
    {
        Program::exec();
    }
    
[/code]

x = (*x)() でなく x = x() を要求される場合は、次のように書けることは書けます。  
C++ の参照は Java や C# の参照と違うためメンバーにポインタを持つしかない。

[code]

    #include <iostream>
    
    class Program {
        class A {
        public:
            A* a_ = 0;
            virtual A &func() { static A a; a_ = &a; return *a_; }
            A &operator =(const A &x) { a_ = x.a_;  return *this; }
            A &operator()() { return a_ ? a_->func() : func(); }
        };
        class F : public A {
        public:
            A &func() override { 
                std::cout << "f";
                static G g; 
                a_ = g.a_ = &g; 
                return *a_;
            }
        };
        class G : public A {
        public:
            A &func() override {
                std::cout << "g";
                static F f;
                a_ = f.a_ = &f;
                return *a_;
            }
        };
    public:
        static void exec() {
            F f;
            A &x = f;
            for (int i = 0; i < 10; ++i) x = x();
        }
    };
    
    int main()
    {
        Program::exec();
    }
    
[/code]


CC BY-SA 4.0
2020-10-17T04:30:11.893
71272
2020-10-17T12:24:03.047
2020-10-17T12:24:03.047
41756
41756
71264
answer


C/C++では自分自身と同じ型を返す関数ポインタ型を直接定義することはできないと思います。

別解として、暗黙の変換コンストラクタを持つ関数オブジェクトを定義すればキャストを省略できます。  
特に仮想関数や継承を使う必要はないです。

C++11以降では可変引数テンプレートを使うことで、一応アダプターの汎用化はできます。

[code]

    #include <cstdio>
    
    template<typename... TArgs> struct MyFuncWrapper {
        using FuncPtr = MyFuncWrapper(*)(TArgs...);
        FuncPtr m_func;
        MyFuncWrapper() = delete;
        // 暗黙の変換コンストラクタ。
        MyFuncWrapper(FuncPtr p) : m_func(p) {
        }
        MyFuncWrapper operator()(TArgs... args) const {
            return m_func(args...);
        }
    };
    
    MyFuncWrapper<> f();
    MyFuncWrapper<> g();
    
    MyFuncWrapper<> f() { std::puts("f"); return g; }
    MyFuncWrapper<> g() { std::puts("g"); return f; }
    
    int main() {
        MyFuncWrapper<> x = f;
        for (int i = 0; i < 10; ++i) {
            x = x();
        }
        return 0;
    }
    
[/code]


CC BY-SA 4.0
2020-10-17T15:39:01.767
71286
2020-10-17T15:39:01.767
15413
71264
answer