2

コンパイル時に適切なオーバーロードされた関数テンプレートを選択する方法を理解しようとしていますが、コンパイラが苦労しています。動作させることはできますが、何が起こっているのかわかりません。説明させてください。

以下のような2つの構造体AとBがあります。1 つは特別な機能を持ち、もう 1 つは通常の機能を持っています。

struct A
{
    void special() { std::cout << "special called.\n"; }
};

struct B
{
    void normal() { std::cout << "normal called.\n"; }
};

私の意図は、特別な関数が利用可能かどうかに応じて、コンパイル時に適切なオーバーロードされた関数テンプレートを選択するメカニズムを持つことです。構造体をパラメーターとして受け取る 2 つの関数を実行して、適切な関数を呼び出すことができるようにします。

template<class Func, Func f> struct Sfinae {};

template <typename U>
static void run(U& u, Sfinae<void (U::*)(), &U::special>* = 0)
{
    u.special();
}

template <typename U>
static void run(U& u, ...)
{
    u.normal();
}

これを次のようにテストしましたが、さまざまな結果が得られました。

int main()
{
    A a;
    run<A>(a, 0); // works
    run<A>(a); // ERROR: ambiguous overloaded function
    run(a, 0); // ERROR: A has no member normal
    run(a); // ERROR: ambiguous overloaded function

    B b;
    run<B>(b, 0); // works
    run<B>(b); // works
    run(b, 0); // works
    run(b); // works

    return 0;
}

run(a)余分な引数や <> なしで使用したいと思います。これが機能しない場合、コードに何か問題がありますか?

また、ここで何が起こっているのか、なぜこれがこのようなことを推測しているのかを理解したいと思って<A>AますB。標準が何を言っているのか、これがコンパイラ間で異なるのかどうかはわかりませんが、少なくともLinuxではgcc4.4.4、Macではgcc 4.0.1が説明したように機能します。

誰かがこれに光を当てることができますか?ありがとう!

4

2 に答える 2

1

ここはうまくいきます。これは、ノーマルとスペシャルの 2 つの関数が相互に排他的であることを前提としています (つまり、どちらか一方を持つクラスにはもう一方がありません)。目的に合わせて調整できると思います。boost::enable_ifもちろん、これは を使用します。

#include <iostream>
#include <boost/utility/enable_if.hpp>

struct A
{
    void special() { std::cout << "special called.\n"; }
};

struct B
{
    void normal() { std::cout << "normal called.\n"; }
};

template<int> struct Sfinae { enum { value = true }; };

template <typename U>
static typename boost::enable_if<Sfinae<sizeof(&U::special)>,void>::type run(U& u)
{
    u.special();
}

template <typename U>
static typename boost::enable_if<Sfinae<sizeof(&U::normal)>,void>::type run(U& u)
{
    u.normal();
}


int main()
{
    A a;
    run(a); // works

    B b;
    run(b); // works

    return 0;
}

これは Linux 上の gcc 4.6.0 で動作します。

于 2011-02-09T20:17:38.390 に答える
1

この特定の状況では、これを行うことができます。これは非常に簡単です。

template <typename U>
static void run(U & u)
{
    u.special();
}

template <>
static void run<B>(B &u)
{
    u.normal();
}

または、単純にテンプレートを削除して、オーバーロードされた関数を 2 つ記述することもできます。私は同意します、これはより一般的な方法では解決しません。

おそらく、このトピックは一般的な解決策を見つけるのに役立ちます:

関数の存在を確認するテンプレートを作成することはできますか?

ヨハネスの答えを見てください。:-)

于 2011-02-09T19:33:46.103 に答える