14

クラスのベクトルのような演算子とマップのような演算子を実装しようとしています[]。しかし、コンパイラ (g++ および clang++) からエラー メッセージが表示されます。クラスに整数型への変換演算子もある場合にのみ発生することがわかりました。

今、私には2つの問題があります。1 つ目は、クラスに int への変換演算子がある場合[](const std::string&)と、コンパイラが区別できない理由がわからないことです。[](size_t)2 つ目は、変換とインデックス演算子が必要です。それを修正する方法は?

作品:

#include <stdint.h>
#include <string>

struct Foo
{
    Foo& operator[](const std::string &foo) {}
    Foo& operator[](size_t index) {}
};

int main()
{
    Foo f;
    f["foo"];
    f[2];
}

動作しません:

#include <stdint.h>
#include <string>

struct Foo
{
    operator uint32_t() {}
    Foo& operator[](const std::string &foo) {}
    Foo& operator[](size_t index) {}
};

int main()
{
    Foo f;
    f["foo"];
    f[2];
}

コンパイラ エラー:

main.cpp: In function 'int main()':
main.cpp:14:9: error: ambiguous overload for 'operator[]' in 'f["foo"]'
main.cpp:14:9: note: candidates are:
main.cpp:14:9: note: operator[](long int, const char*) <built-in>
main.cpp:7:7: note: Foo& Foo::operator[](const string&)
main.cpp:8:7: note: Foo& Foo::operator[](size_t) <near match>
main.cpp:8:7: note:   no known conversion for argument 1 from 'const char [4]' to 'size_t {aka long unsigned int}'
4

3 に答える 3

2

他の回答で述べたように、あなたの問題は[]デフォルトで通勤することです -はfora[b]と同じであり、クラスがこれに変換可能であることは、に変換されることと同じくらい良い一致です。b[a]char const*uint32_tchar*std::string

私がここで提供しているのは、オーバーロードが呼び出されるべきだと信じているにもかかわらず呼び出されない、まさにこの種の問題を抱えている場合に備えて、「非常に魅力的なオーバーロード」を作成する方法です。

したがって、ここFooに の「非常に魅力的なオーバーロード」がある がありstd::stringます。

struct Foo
{
  operator uint32_t() {return 1;}
  Foo& lookup_by_string(const std::string &foo) { return *this; }
  Foo& operator[](size_t index) {return *this;}
  template<
    typename String,
    typename=typename std::enable_if<
      std::is_convertible< String, std::string >::value
    >::type
  > Foo& operator[]( String&& str ) {
    return lookup_by_string( std::forward<String>(str) );
  }
};

ここで、独立した「文字列によるルックアップ」関数を作成し、に変換できる任意のstd::string型をキャプチャするテンプレートを作成します。

ユーザー定義の変換が template の本体内に「隠蔽」されるoperator[]ため、一致をチェックするときにユーザー定義の変換が発生しないため、ユーザー定義の変換を必要とする他の操作 ( などuint32_t[char*]) よりも優先されます。実際、これは、引数が正確に一致しないオーバーロードよりも "魅力的な" オーバーロードです。

これは問題を引き起こす可能性があります. を受け取り、 への変換を持つ別のオーバーロードがあるconst Bar&場合Barstd::string上記のオーバーロードはあなたを驚かせ、渡されたものをキャプチャする可能性がありますBar.rvalue と非 const 変数の両方[][const Bar&]!

于 2013-04-06T13:30:49.350 に答える