20

<type_traits>ある型が別の型に明示的に変換可能かどうかを (精神的に) 判断する方法は? たとえば、F::explicit operator double const & () const;一部のclass/の存在を確認したいのですstruct Fが、同時にor (のようなもの)Fに明示的に変換可能であってはなりません。floatlong doublepred< double const & >::value && !pred< float >::value && !pred< long double >::value

「暗黙的な変換を使用してFromをToに変換できるstd::is_convertible< From, To >::valueかどうか」をチェックすることに注意してください。しかし、明示的な変換演算子があるかどうかを判断したいと思います。

そして、可能であれば、「タイプFromをタイプToの参照に変換できるかどうかを判断する方法は?」

4

2 に答える 2

12

あなたのテスト セットはオフサイト リンクにあり、元の投稿から変更されているため、ここで話しているテスト セットをそのままコピーします。

static_assert(is_explicitly_convertible< double, double >::value, "1");
static_assert(is_explicitly_convertible< double &, double >::value, "2");
static_assert(is_explicitly_convertible< double const, double >::value, "3");
static_assert(is_explicitly_convertible< double const &, double >::value, "4");

static_assert(is_explicitly_convertible< double, double const & >::value, "5");
static_assert(is_explicitly_convertible< double &, double const & >::value, "6");
static_assert(is_explicitly_convertible< double const, double const & >::value, "7");
static_assert(is_explicitly_convertible< double const &, double const & >::value, "8");

static_assert(!is_explicitly_convertible< double, double & >::value, "9"); // not a ref
static_assert(is_explicitly_convertible< double &, double & >::value, "10");
static_assert(!is_explicitly_convertible< double const, double & >::value, "11");
static_assert(!is_explicitly_convertible< double const &, double & >::value, "12");

static_assert(is_explicitly_convertible< double, double const >::value, "13");
static_assert(is_explicitly_convertible< double &, double const >::value, "14");
static_assert(is_explicitly_convertible< double const, double const >::value, "15");
static_assert(is_explicitly_convertible< double const &, double const >::value, "16");

static_assert(is_explicitly_convertible< AA const &, A const & >::value, "=&1.a");
static_assert(is_explicitly_convertible< CC const &, C const & >::value, "=&1.b");
static_assert(is_explicitly_convertible< BB const &, B const & >::value, "=&1.c");
static_assert(!is_explicitly_convertible< AA const &, A & >::value, "&1.a");
static_assert(!is_explicitly_convertible< CC const &, C & >::value, "&1.b");
static_assert(!is_explicitly_convertible< BB const &, B & >::value, "&1.c");

static_assert(is_explicitly_convertible< AA const, A const & >::value, "=1.a");
static_assert(is_explicitly_convertible< CC const, C const & >::value, "=1.b");
static_assert(is_explicitly_convertible< BB const, B const & >::value, "=1.c");
//static_assert(!is_explicitly_convertible< AA const, A >::value, "=2.a"); // ???????????????
//static_assert(!is_explicitly_convertible< CC const, C >::value, "=2.b");
//static_assert(!is_explicitly_convertible< BB const, B >::value, "=2.c");
static_assert(!is_explicitly_convertible< AA const, A & >::value, "=3.a"); // good!
static_assert(!is_explicitly_convertible< CC const, C & >::value, "=3.b"); //
static_assert(!is_explicitly_convertible< BB const, B & >::value, "=3.c"); //
static_assert(!is_explicitly_convertible< AA const, A && >::value, "=4.a"); // not interesting
static_assert(!is_explicitly_convertible< CC const, C && >::value, "=4.b"); //
static_assert(!is_explicitly_convertible< BB const, B && >::value, "=4.c"); //
static_assert(!is_explicitly_convertible< AA const, B const & >::value, "=5.a");
static_assert(!is_explicitly_convertible< AA const, C const & >::value, "=5.b");
static_assert(!is_explicitly_convertible< BB const, A const & >::value, "=5.c");
static_assert(!is_explicitly_convertible< BB const, C const & >::value, "=6.a");
static_assert(!is_explicitly_convertible< CC const, A const & >::value, "=6.b");
static_assert(!is_explicitly_convertible< CC const, B const & >::value, "=6.c");
static_assert(!is_explicitly_convertible< AA const, B & >::value, "=7.a");
static_assert(!is_explicitly_convertible< AA const, C & >::value, "=7.b");
static_assert(!is_explicitly_convertible< BB const, A & >::value, "=7.c");
static_assert(!is_explicitly_convertible< BB const, C & >::value, "=8.a");
static_assert(!is_explicitly_convertible< CC const, A & >::value, "=8.b");
static_assert(!is_explicitly_convertible< CC const, B & >::value, "=8.c");
static_assert(!is_explicitly_convertible< AA const, B >::value, "=9.a"); // very subtle moment (see class AA above)
static_assert(!is_explicitly_convertible< AA const, C >::value, "=9.b");
static_assert(is_explicitly_convertible< BB const, A >::value == std::is_constructible< A, A && >::value, "=9.c"); // (see class BB above)
static_assert(!is_explicitly_convertible< BB const, C >::value, "=10.a");
static_assert(!is_explicitly_convertible< CC const, A >::value, "=10.b");
static_assert(!is_explicitly_convertible< CC const, B >::value, "=10.c");

static_assert(is_explicitly_convertible< AA, A & >::value, "~1.a");
static_assert(is_explicitly_convertible< CC, C & >::value, "~1.b");
static_assert(is_explicitly_convertible< BB, B & >::value, "~1.c");
//static_assert(!is_explicitly_convertible< AA, A >::value, "~2.a"); // ???????????????
//static_assert(!is_explicitly_convertible< CC, C >::value, "~2.b");
//static_assert(!is_explicitly_convertible< BB, B >::value, "~2.c");
static_assert(is_explicitly_convertible< AA, A const & >::value, "~3.a"); // convertible
static_assert(is_explicitly_convertible< CC, C const & >::value, "~3.b"); //
static_assert(is_explicitly_convertible< BB, B const & >::value, "~3.c"); //
static_assert(!is_explicitly_convertible< AA, B const & >::value, "~4.a");
static_assert(!is_explicitly_convertible< AA, C const & >::value, "~4.b");
static_assert(!is_explicitly_convertible< BB, A const & >::value, "~4.c");
static_assert(!is_explicitly_convertible< BB, C const & >::value, "~5.a");
static_assert(!is_explicitly_convertible< CC, A const & >::value, "~5.b");
static_assert(!is_explicitly_convertible< CC, B const & >::value, "~5.c");

static_assert(std::is_convertible< double, double const & >::value, "5*");
static_assert(!std::is_convertible< double, double & >::value, "9*");

gcc 4.7.2 を利用している場合 (それ以前は確認していない可能性があります)、C++11 標準ライブラリが問題を解決します。

std::is_explicitly_convertible<From,To>

で定義されています<type_traits>

ただし、そのバージョンの C++11 標準ライブラリではエラーが発生します。この特性テンプレートは、N3047 (2010) に従って標準から削除されたため、そこにあるべきではありませんでした。

もしあなたが gcc 4.8.1 (またはおそらく 4.8; 私はチェックしていません) を使用している場合、この特性はもはやライブラリーにありません。

しかし、最初に gcc 4.7.2 の定義を検査するのは人間だけであり<type_traits> 、それを行うと、GNU 実装者が特性を の逆に過ぎないと見なしたことが明らかになりますstd::is_constructible<To,From>

/// is_explicitly_convertible
template<typename _From, typename _To>
struct is_explicitly_convertible
: public is_constructible<_To, _From>
{ };

と思うかもしれませんが、もちろんです。

では、なぜそれがうまくいかないのでしょうか。N3047 は次のように説明しています。

残りの問題は、影響を受けたis_explicitly_convertible特性をどのように修復するかです。基本的な選択肢は次のとおりです。

  1. 現在の static_cast 式に戻って修正し、 に依存しis_explicitly_convertibleなくなりました。is_explicitly_convertibleis_constructible
  2. 標準から削除is_explicitly_convertibleします。

最初の選択肢が検討されましたが、「明示的に変換可能」が実際に何を意味するかについて、まったく異なる理解が存在することが判明しました。がこれを正しく表現していると信じている人もstatic_castいれば、fixedis_constructibleの方がより良い意味を提供すると信じている人is_explicitly_convertibleもいます。したがって、この文書でis_explicitly_convertibleは、作業草案から を削除することをお勧めします。その特別な定義にはまだ何も依存していないため、これは今のところ害を及ぼすことはありません。また、その特性がまだ有用であることが判明した場合は、標準の別の改訂で追加される可能性があります。

その定義には既知のバグはありませんでしたが、それが成文化する「明示的に変換可能」の意味が正しいものであるかどうかについて、反対の見解がありました:-

  • D1) =dfFromに明示的に変換可能です。ToToFrom
  • D2) =dfFromに明示的に変換可能であり、静的にキャストできます。ToFromTo

私はこの論争に異議を唱えるつもりはありませんが (私自身、違いが何であるかを理解していません)、お金を払って選択することをお勧めします。

D1) を支持する場合は、<type_traits>上記のように gcc 4.7.2 から特性の定義を単純に取得できます。

D2 を支持する場合はstd::is_convertible<From,To> 、gcc 4.8.1の定義を盗用して適応させることができます<type_traits>。この定義は、追跡する必要がある内部補助機能を呼び出します。From必要な適応は、 can be のテストに暗黙的にキャストできる ToSFINAE テストを can be to に変更するFromことstatic_castですTo。そして、それは以下を置き換えることを意味します:

  template<typename _From1, typename _To1>
    static decltype(__test_aux<_To1>(std::declval<_From1>()), __one())
__test(int);

と:

  template<typename _From1, typename _To1>
    static decltype(__test_aux<_To1>(static_cast<_To1>(std::declval<_From1>())), __one())
__test(int);

あなたの s でテストされる型に対して行う、この定義の縮小バージョン ( 関数または配列型である、および関数または配列型Fromであるなどのケースを無視する) :voidTostatic_assert

template<typename From, typename To>
struct is_explicitly_convertible
{
    template<typename T>
    static void f(T);

    template<typename F, typename T>
    static constexpr auto test(int) -> 
    decltype(f(static_cast<T>(std::declval<F>())),true) {
        return true;
    }

    template<typename F, typename T>
    static constexpr auto test(...) -> bool {
        return false;
    }

    static bool const value = test<From,To>(0);
};

D1 定義または削減された D2 定義のいずれかが、63 個すべての を支持しますstatic_assert。(私は g++ 4.7.2 と 4.8.1 でコンパイルし-g;-O0;-Wall;-std=c++11ました。また-std=gnu++1y、あなたが採用した でコンパイルしました)

あなたの最新のソリューションは、異なるスタイルの実装を使用して、D2 スクールへの道を進んだことを示しています。

2つのうち、何か問題が見つかるまでは、gcc 4.7.2のようにD1の定義を好み std::is_constructibleます.

于 2013-06-05T15:38:56.630 に答える