6

T&&普遍的な参照 ( ) は、あらゆる種類の参照を取ることになっていると思いました。しかし、以下は機能しません。

私が書いているライブラリで const-correct をしようとすると、この問題に遭遇します。私は C++ が初めてで、このようなものを見たことがありません。

test.cpp:

enum Cv_qualifier {
    constant,
    non_const
};
template <Cv_qualifier Cv> class A;
template<>
class A<Cv_qualifier::constant> {
public:
    template<Cv_qualifier Cv2> 
    void t(const A<Cv2>&& out) {}
};

template <>
class A<Cv_qualifier::non_const> {
public:
    template<Cv_qualifier Cv2> 
    void t(const A<Cv2>&& out) {}
};

int main()
{
    A<Cv_qualifier::non_const> a;
    A<Cv_qualifier::constant> b;
    a.t(b);
}

エラー (でコンパイルg++ test.cpp -std=c++11):

test.cpp: In function ‘int main()’:
test.cpp:24:10: error: cannot bind ‘A<(Cv_qualifier)0u>’ lvalue to ‘const A<(Cv_qualifier)0u>&&’
     a.t(b);
          ^
test.cpp:17:10: note:   initializing argument 1 of ‘void A<(Cv_qualifier)1u>::t(const A<Cv2>&&) [with Cv_qualifier Cv2 = (Cv_qualifier)0u]’
     void t(const A<Cv2>&& out) {}
          ^

ちなみに、実際のプログラムでは、class Aは実際のデータを所有しておらず、実際にデータを保持している別のクラスへの参照を含んでいます。tこれは、メンバー関数がclass A一時オブジェクトを受け入れることを許可するときに、間接/コピー データを常に作成していないことを意味することを願っています。

4

1 に答える 1

6

ユニバーサル参照、または転送参照は、参照の崩壊が原因でのみ発生します。そのように動作します:

T&& & -> T&
T& && -> T&
T&& && -> T&&

そうすれば、テンプレート関数で受け取るT&&と、右辺値参照は、のタイプに応じて他のタイプの参照に折りたたむことができますT。それ以外の場合、折りたたみが発生しない場合はそのままで、右辺値参照になりますSomeType&&SomeType&&

そうは言っても、関数で転送をサポートしたい場合は、次のようにすることができます。

template <Cv_qualifier Cv> struct A;

template<>
struct A<Cv_qualifier::constant> {
    template<typename T> 
    void t(T&& out) {}
};

template <>
struct A<Cv_qualifier::non_const> {
    template<typename T> 
    void t(T&& out) {}
};

確かに、今、崩壊が起こっています。Cv_qualifierから値を抽出したい場合はT、それを行う型特性を自分で作成できます。

template<typename>
struct CvValue;

template<Cv_qualifier cv>
struct CvValue<A<cv>> {
    constexpr static Cv_qualifier value = cv;
};

次に、 function 内tで、次のことができます。

//                   v----- This is a good practice to apply a constraint
template<typename T, std::void_t<decltype(CvValue<std::decay_t<T>>::value)>* = 0> 
auto t(T&& out) {
    constexpr auto cv = CvValue<std::decay_t<T>>::value;

    // do whatever you want with cv
}

C++17 の を使用できない場合は、次のstd::void_tように実装できます。

template<typename...>
using void_t = void;

ただし、 が であるかどうかのみをテストする場合Tは、A<...>次を使用します。

template<typename>
struct is_A : std::false_type {};

template<Cv_qualifier cv>
struct is_A<A<cv>> : std::true_type {};

で使用することを忘れないでくださいstd::decay_t

template<typename T, std::enable_if_t<std::is_A<std::decay_t<T>>::value>* = 0> 
void t(T&& out) {}
于 2016-11-15T21:13:38.820 に答える