次のコード スニペットを考えてみましょう。これは、推定される型に特化したクラス テンプレートのインスタンスを関数テンプレートに構築させるという一般的なイディオムを使用しています。たとえば、std::make_unique
andstd::make_tuple
で見られます。
template <typename T>
struct foo
{
std::decay_t<T> v_;
foo(T&& v) : v_(std::forward<T>(v)) {}
};
template <typename U>
foo<U> make_foo(U&& v)
{
return { std::forward<U>(v) };
}
Scott Meyers の「ユニバーサル リファレンス」のコンテキストでは、引数 to
はmake_foo
ユニバーサル リファレンスです。のコンストラクターへの引数は、その型は ですが、(一般に) 推定されないため、ユニバーサル参照ではありません。U&&
U
foo
T&&
T
しかし、 のコンストラクターがfoo
によって呼び出される場合、 のコンストラクターへの引数をユニバーサル参照であるmake_foo
と考えるのは理にかなっているように思えます。関数 template によって推定されているからです。の型が両方の関数で同じになるように、同じ参照折りたたみルールが適用されます。この場合、 と の両方が演繹された
と言えます。foo
T
make_foo
v
T
U
だから私の質問は2つあります:
- 私の例のように、呼び出し元によってユニバーサル参照コンテキスト内で推定され
foo
た限られたケースで、コンストラクターへの引数をユニバーサル参照であると考えるのは理にかなっていますか?T
- 私の例では、両方とも
std::forward
賢明な使用ですか?