7

プロジェクトを Visual Studio 2010 から Visual Studio 2012 に移植しようとしています。コードには、次のようなファイル処理があります。

auto fileDeleter = [](FILE* f) { fclose(f); };

unique_ptr<FILE, decltype(fileDeleter)> fMinute(
    fopen(minuteLogName.c_str(), "w"), fileDeleter);


unique_ptr<FILE, decltype(fileDeleter)> fIndividual(
    fopen(individualLogName.c_str(), "w"), fileDeleter);

if (!fMinute || !fIndividual) {
    throw Exceptions::IOException("One of the log files failed to open",
                                  __FUNCTION__);
}

これは 2010 年には問題なくビルドされましたが、2012 年には次の条件で失敗します。

エラー C2678: バイナリ '!' : タイプ > 'std::unique_ptr<_Ty,_Dx>' の左側のオペランドを取る演算子が見つかりません (または、受け入れ可能な変換がありません)
...
'built-in C++ operator!(bool)' である可能性があります

C++11 標準では、unique_ptr に bool 演算子があり、上記のようなクイック チェックを実行できるように指定されています。まだ見知らぬ人ですが、VS2012 の unique_ptr 定義には、まさにこの演算子があります。

_OPERATOR_BOOL() const _NOEXCEPT
{   // test for non-null pointer
    return (this->_Myptr != pointer() ? _CONVERTIBLE_TO_TRUE : 0);
}

しかし、コンパイル時にそのエラーが発生します。なんで?

ofstreamはい、代わりに使用することもできますが、それは重要ではありません。

4

3 に答える 3

6

BigBoss の発言に基づいて構築するには、C++11 ではstd::unique_ptruseが必要ですexplicit operator bool() noexcept。これにより、bool への暗黙的な変換全体が解決されます。ただし、VC2012 はまだ演算子をサポート explicitしていません。したがって、それらはsafe-bool イディオムを使用する必要があります。

safe-bool イディオムは優れていexplicit operator bool()ますが、イディオムの実装方法によっては、欠陥がある可能性があります (これが存在する理由です)。そして、あなたは VC2012 でそれらの 1 つに出くわしたようです。を使用してテストを再構成すると!(fMinute && fIndividual)、問題が解決するはずです。

いずれにせよ、これは Visual Studio のバグです。動作が変更されたため、回避方法が見つかったとしても、バグ レポートを提出する必要があります。

于 2012-10-20T23:41:37.517 に答える
1

if (!(fMinute && fIndividual) )の代わりに使用できますif (!fMinute || !fIndividual)。C ++は、ブール値に変換可能であると言っていますが、通常は問題が発生します。たとえば、クラスにthenがある場合、それはintに変換可能であり、この関数に渡すことができますが、たとえばこのoperator bool場合は、を受け入れる関数がある可能性があります。として使用することを意図したものではないため、多くの開発者は直接使用することはなく、代わりに条件式でブール値として使用できる演算子を記述しますが、実際にはブール値ではありません。intoperator boolunique_ptrintoperator bool

struct bool_convertible {
    typedef void (*convertible_to_bool)();
    static void convertible_to_true();
    operator convertible_to_bool () const {
        return test() ? &convertible_to_true : nullptr;
    }
};

このテクニックを使用すると、私は持っているかもしれませんbool_convertible c; if( c ) {...}が、私は持つことができません

void test_int( int );
bool_convertible c;
test_int( c );
于 2012-10-20T23:29:14.747 に答える
1

最近の C++11 標準では、std::unique_ptr はoperator!定義されておらず、明示的な変換演算子のみが定義されています。

explicit operator bool() const;

ただし、組み込みの単項論理否定演算子 は!、5.3.1/9 に従って、コンテキストに応じてその引数を bool に変換します。

論理否定演算子のオペランドは、!文脈に応じてbool(節 4) に変換されます。その値は、変換されたオペランドが false の場合は true、それ以外の場合は false

bool へのコンテキスト変換では、利用可能な場合、明示的な変換演算子が使用されます。そのため、コードは実際には C++11 ルールの下で動作することが期待されています。Microsoft にバグ レポートを提出する必要があります。明示的な変換演算子をサポートするかどうかは問題ではありません。

回避策として、これを試してください:

if (!fMinute.get() || !fIndividual.get()) {
    ....
于 2012-10-20T23:50:18.990 に答える