3

特定のクラスに<<(cls, ostream)演算子が定義されているかどうかを確認する必要があります。もしそうなら、私は自分の関数がそれを使って に書き込むことを望みますostringstream。それ以外の場合は定型コードを使用する必要があります。

私はこの質問が以前に尋ねられたことを知っています。ただし、通常、コンパイラ (clang++) で常に機能するとは限らないカスタム ソリューションを見つけます。何時間も検索した後、私はついにそのboost::type_traitsを見つけました。c++ 11 が既にブーストの特性部門のすべてをコピーしていると想定していたため、以前はそこを見ていませんでした。

私にとってうまくいった解決策は、次のことでした。

template <typename C>
std::string toString(C &instance) {
    std::ostringstream out;
    out << to_string<C, boost::has_left_shift<C, std::ostream>::value>::convert(ctx);
    return out.str();
}

次のようにto_string定義されています。

template <typename C, bool>
struct to_string {
    // will never get called
    static std::string convert(LuaContext &ctx) {}
};

template <typename C>
struct to_string<C, true> {
    static std::string convert(LuaContext &ctx) {
        return "convert(true) called.";
    }
};

template <typename C>
struct to_string<C, false> {
    static std::string convert(LuaContext &ctx) {
        return "convert(false) called.";
    }
};

だから私は2つの理由でこれを投稿しています:

  1. これが使用するのに最も健全な方法であるかどうかを確認するか、他の誰かがさらに良い解決策を提案できるかどうかを確認します (つまり、質問は「これは機能しますか?」というよりも、アプローチの好奇心からのものです-私にとっては既に機能しています)

  2. これを投稿して、誰かが同様のことをする必要がある場合に備えて、検索の時間を節約してください。

  3. より一般的な質問として - 特性クラスが std::true_type または std::false_type を返すように見えることがあります (少なくとも非ブースト クラスの場合)。それ以外の場合はブール値です。この不一致には理由がありますか? boost:has_left_shiftの代わりに型が返された場合、構造体boolを 1 つだけ持つことができますto_string

4

1 に答える 1

8

手っ取り早い C++11 SFINAE:

template<typename T,
         typename = decltype(
           std::declval<std::ostream&>() << std::declval<T const&>()
         )
>
std::string toString(T const& t)
{
    std::ostringstream out;
    // Beware of no error checking here
    out << t;
    return out.str();
}

template<typename T,
         typename... Ignored
>
std::string toString(T const& t, Ignored const&..., ...)
{
    static_assert( sizeof...(Ignored) == 0
                 , "Incorrect usage: only one parameter allowed" );
    /* handle any which way here */
}

stream << val必要に応じて、 の戻り値の型が実際に に変換可能であることも確認できますstd::ostream&

template<typename T,
         typename Result = decltype(
           std::declval<std::ostream&>() << std::declval<T const&>()
         ),
         typename std::enable_if<
             std::is_convertible<Result, std::ostream&>::value,
             int
         >::type = 0
>

それほど簡単ではない解決策is_stream_insertableとして、ここで使用されているのとまったく同じトリックを実装で利用できる特性を紹介します。

std::integral_constant<bool, B>には への変換演算子があることに注意してくださいbool。これにより、観察したいくつかのことが説明される場合があります。std::true_typeまた、C++11 標準の型と特性を Boost と混在させることもお勧めしませんboost::true_type。これは、たとえば Boost.TypeTraits を C++11 でまったく使用してはならないということではありませんが、一貫性を保ち、一度に 2 つのうちの 1 つだけを使用するようにしてください。

于 2012-10-19T20:54:02.157 に答える