1

拡張関数がnon-constとconstの両方に適切に一致する可変個引数テンプレートを作成するのに問題がありますstd::string。代わりに呼び出される一般的なマッチング関数があります。

コードを以下の例に減らしました。文字列ではないものは、ジェネリック関数で終わるはずです。文字列であるものは、さらに「STRING」を出力する2番目の関数で終わるはずです。

#include <iostream>
#include <string>

template<typename X, typename T>
void extend_exception( X & ex, T&& value )
{
    ex << value << std::endl;
}

template<typename X>
void extend_exception( X & ex, std::string && value )
{
    ex << "STRING: " << value << std::endl;
}

template<typename X, typename TF, typename ... TR>
void extend_exception( X & ex, TF&& f, TR&& ... rest )
{
    extend_exception( ex, std::forward<TF>(f) );
    extend_exception( ex, std::forward<TR>(rest)... );
}

int main()
{
    extend_exception( std::cout, std::string( "Happy" ) );
    std::string var( "var" );
    extend_exception( std::cout, var );
    extend_exception( std::cout, var, std::string( "Combo" ),  const_cast<std::string const&>(var));
    return 0;
}

上記のバージョンでは、2つのvar使用法は文字列関数に渡されません。パラメータを指定する他のさまざまな方法を試しましたが、どれもうまくいかないようです:std::string && value、、。また、const以外の文字列は一致しましたが、constの文字列は一致しませんでした。これにより、少なくとも2つの異なる機能を使用することで回避策が得られますが、これを行う必要はないと思います。std::string const & valuestd::string const && valuestd::string & value

const、non-const、および一時的な文字列オブジェクトに対して呼び出される単一の関数をここに作成するにはどうすればよいですか?

g++4.6.3を使用しています

4

4 に答える 4

4

これはかなりトリッキーで、T&&いわゆるユニバーサル参照ですが、そうでstd::string&&はありません (型推定は含まれません)。良い説明については、こちらを参照してください。ここに修正があります:

template<typename X, typename T>
void extend_exception_( X & ex, T&& value, ... )
{
  ex << value << std::endl;
}

template<typename X, typename T,
         typename = typename std::enable_if<
           std::is_same<std::string, typename std::decay<T>::type>::value>::type>
void extend_exception_( X & ex, T && value, int )
{
  ex << "STRING: " << value << std::endl;
}

template <typename T> using identity = T;

template<typename X, typename ... R>
void extend_exception( X & ex, R&& ... rest )
{
  identity<bool[]>{false,(extend_exception_(ex, std::forward<R>(rest), 0), false)...};
}

int main()
{
  extend_exception( std::cout, std::string( "Happy" ) );
  std::string var( "var" );
  extend_exception( std::cout, var );
  extend_exception( std::cout, var, std::string( "Combo" ) );
}
于 2013-01-09T16:27:09.540 に答える
2

非右辺値を右辺値参照にバインドすることはできないため、string&&機能しませんがconst std::string&var. ただし、varは const ではないため、機能するオーバーロードへの最短パスは、最初のものに折りたたんで取得することですT&&std::string&

相互に排他的な型を把握するか、SFINAE を使用して、正しい型の引数で相互に排他的な 2 つの型を記述する必要があります。

于 2013-01-09T16:27:10.173 に答える
2

これは、文字列バージョンが右辺値として渡された文字列のみをキャプチャするためです。左辺値はジェネリック関数に渡されます。T&& と string&&、またはより一般的な T&& と U&& の間には大きな違いがあります (T がテンプレート パラメーターであり、U がそうでない場合 (つまり、U は特定の型))。ユニバーサル リファレンスに関する Scott Meyers のメモを参照してください。

関数を希望どおりに機能させるために必要なことは、さらに別のオーバーロードを追加することです。

template<typename X>
void extend_exception( X & ex, std::string const& value )
{
  ex << "STRING: " << value << std::endl;
}
于 2013-01-09T16:32:04.887 に答える
0

私は問題を再検討し、クラス マーカーの使用を含む解決策を思いつきました。完全なソリューション/ディスカッションを含む記事を書きました。

于 2013-06-03T07:22:53.017 に答える