1. ホーム
  2. c++

[解決済み] なぜ関数を別の関数の中で定義できないのですか?

2023-07-13 14:35:48

質問

ラムダ関数を変数に代入できることは知っています。

コード内部で関数を宣言することはできても、定義することができないのはどういうことでしょうか?

例えば

#include <iostream>

int main()
{
    // This is illegal
    // int one(int bar) { return 13 + bar; }

    // This is legal, but why would I want this?
    int two(int bar);

    // This gets the job done but man it's complicated
    class three{
        int m_iBar;
    public:
        three(int bar):m_iBar(13 + bar){}
        operator int(){return m_iBar;}
    }; 

    std::cout << three(42) << '\n';
    return 0;
}

そこで私が知りたいのは、なぜ C++ は two という無駄と思われるものを許し three という、はるかに複雑に見えるものがありますが、これは one ?

EDITです。

回答から、コード内の宣言で名前空間汚染を防ぐことができそうです。しかし、私が聞きたかったのは、なぜ関数を宣言する機能は許可されているのに、関数を定義する機能は禁止されているのか、ということです。

どのように解決するのですか?

なぜ one が許されない理由は明らかではありません。ネストされた関数は、ずっと以前に N0295 と言うものです。

C++にネストされた関数が導入されたことについて説明します。ネストされた 関数はよく理解されており、その導入にはコンパイラーベンダー、プログラマー、委員会のいずれもがほとんど コンパイラーベンダー、プログラマー、委員会のいずれからもほとんど努力は必要ありません。 ネストされた関数は重要な利点を提供します。

明らかにこの提案は却下されましたが、会議の議事録がオンラインで利用できないので 1993 の会議録がオンラインで利用できないため、この却下の根拠となる可能性のあるソースがありません。

実際この提案は C言語のラムダ式とクロージャ ++ を代替とすることができます。

ある記事[Bre88]とC++委員会への提案N0295[SH93]は、C++にネストした関数を追加することを提案しています。 委員会への提案 N0295 [SH93] は、C++にネストされた関数を追加することを提案しています。 ++ . ネストされた関数はラムダ式に似ているが、関数本体内のステートメントとして定義され、結果として生じるクロージャはその関数がアクティブでない限り使用できない。 クロージャは、その関数がアクティブでない限り、使用することができません。今回の提案 また、ラムダ式ごとに新しい型を追加するのではなく、通常の関数に近い形で実装し より通常の関数に近い形で実装する。 特別な関数ポインタでラムダ式を参照できるようにする。どちらの提案も これらの提案は、C++にテンプレートが追加される前に行われました。 ++ にテンプレートが追加される以前のものなので、ジェネリックアルゴリズムと組み合わせたネストされた関数の使用については言及していません。また、これらの提案には、ローカル変数をクロージャにコピーする方法が ありません。 また、これらの提案にはローカル変数をクロージャにコピーする方法がないため、生成されるネストされた関数はそのエンクロージャの外では全く使用できません。 を生成する入れ子関数は、その包含する関数の外側では完全に使用できません。

私たちが今ラムダを持っていることを考えると、ネストされた関数を見ることはないでしょう。なぜなら、この論文が概説するように、それらは同じ問題に対する代替案であり、ネストされた関数はラムダと比較していくつかの制限があるためです。

あなたの質問のこの部分に関して。

// This is legal, but why would I want this?
int two(int bar);

欲しい関数を呼び出すのに便利な方法である場合があります。C++標準の草案では、セクション 3.4.1 [基本.lookup.unqual]。 は、1つの興味深い例を与えてくれます。

namespace NS {
    class T { };
    void f(T);
    void g(T, int);
}

NS::T parm;
void g(NS::T, float);

int main() {
    f(parm); // OK: calls NS::f
    extern void g(NS::T, float);
    g(parm, 1); // OK: calls g(NS::T, float)
}