6

次のコードで、理解できない動作が見られます。operator()ポイントは、次のいずれかのような2 番目のオーバーロードを宣言する場合です。

bool operator()(T other) const
bool operator()(const T &other) const

プログラムの出力は次のとおりです。

ストリング

しかし、次の宣言を使用すると:

bool operator()(T &other) const

出力は次のようになります。

他のタイプ

operator()(const string &other)後者の場合に呼び出されない理由を誰か説明してもらえますか?

#include "boost/variant/variant.hpp"
#include "boost/variant/apply_visitor.hpp"

using namespace std;
using namespace boost;

typedef variant<string, int> MyVariant;


class StartsWith
    : public boost::static_visitor<bool>
{
public:
    string mPrefix;
    bool operator()(const string &other) const
    {
        cout << "string" << endl;
        return other.compare(0, mPrefix.length(), mPrefix) == 0;
    }
    template<typename T>
    bool operator()(T &other) const
    {
        cout << "other type" << endl;
        return false;
    }
    StartsWith(string const& prefix):mPrefix(prefix){}
};

int main(int argc, char **argv) 
{
    MyVariant v(string("123456"));
    apply_visitor(StartsWith("123"), v);
    return 0;
}
4

1 に答える 1

6

constここで問題があります。

const オブジェクトを渡していないapply_visitorため、const オブジェクトのメンバーは適用されたビジターに渡されません。したがって、あなたの場合はstring&- 文字列型への参照です。このテンプレートはそれと完全に一致します:

template<typename T>
bool operator()(T &other) const

だから選ばれる。この関数は完全一致ではありません - スキップされます:

bool operator()(const string &other) const

もちろん、その演算子を提供する場合:

bool operator()(string &other) const

非テンプレート関数はテンプレート 1 の前に考慮されるため、それが選択されます。

したがって、解決策は次のとおりです。ビジターに文字列参照(constではない)を取るメソッドを提供するか、constバリアントを渡して適用します...

最初の解決策 - 文字列演算子から const を削除します。

bool operator()(/*const*/ string &other) const
//              ^^^^^^^^^ remove it

2 番目の解決策 - const オブジェクトを渡します。

const MyVariant& cv = v;
apply_visitor(StartsWith("123"), cv);
//                               ^^ const object passed here

3 番目の解決策 - 一般的なビジターに const 指定子を追加します。

template<typename T>
bool operator()(const T &other) const
//              ^^^^^ 

ソリューション 1 番目と 3 番目は 2 番目よりも優れています。一貫したビジターをバリアントに渡す必要があります。const は、コンパイラが適切な関数を選択する必要がある場合に強い意味を持ちます。

于 2012-11-10T07:34:42.413 に答える