3

継承可能なコンストラクターはまだg++で実装されていないため、それらの動作を模倣しようとしています。

https://stackoverflow.com/a/5411992/234261で説明されている手法を試しましたが、独自のコンストラクターを追加したいときに問題が発生します。具体的には、特殊なコピーコンストラクターを追加し、他のすべてのコンストラクターを継承しようとしています。残念ながら、継承された、より一般的なコピーコンストラクターが常に代わりに呼び出されます。

#include <iostream>
struct A {
  A(){}
  A(const A &){ std::cout << "IN A" << std::endl; }
};

struct B : public A{
  template<typename ...Args,
           typename = typename std::enable_if
      <
             std::is_constructible<A, Args...>::value
             >::type>
  B(Args &&...args)
    : A(std::forward<Args>(args)...) {}

  // These don't work either.                                                                                                                
  //B(const A &a):A(a){ std::cout << "IN B-A" << std::endl; }                                                                                
  //B(const B &b):A(b){ std::cout << "IN B-B" << std::endl; }                                                                                
};
template<>
B::B(const A &a):A(a){ std::cout << "IN B-A" << std::endl; }
template<>
B::B(const B &b):A(b){ std::cout << "IN B-B" << std::endl; }

int main(){
  A a;      // 1. Prints nothing as expected                                                                                                    
  B b(a);   // 2. Prints "IN A" only                                                                                                              
  B b1(b);  // 3. Prints "IN A" only                                                                                                              
  return 0;
}

[3]でINA、次にINBBを印刷したいと思います。どういうわけか、実際のコードで[2]を機能させることができましたが、何らかの理由でこの小さな例では繰り返すことができません。

サブクラス(B)を実際に使用してスーパークラス(A)を構築できるため、テンプレートコンストラクターが作成されていることを理解しています。

しかし、なぜ私の明示的なスペシャライゼーションが呼び出されないのですか?私は間違って専門化していますか?もっと良い方法はありますか?


誰かがそれを実行したい場合は、この例にリンクしてくださいhttp://ideone.com/eUHD5

gcc4.6を使用しています

4

2 に答える 2

4

次の「作品」:

struct B : public A
{
    template<typename ...Args, typename = typename std::enable_if<std::is_constructible<A, Args...>::value>::type>
    B(Args &&...args) : A(std::forward<Args>(args)...) {}

    B(const A & a) : A(a){ std::cout << "IN B-A" << std::endl; }
    B(const B & b) : A(b){ std::cout << "IN B-B" << std::endl; }
};


int main()
{
    A a;
    B b(a);
    B b1(static_cast<B const &>(b)); 
}

これは古いテンプレートであり、過負荷はより適切に一致する栗です。詳細な説明については、 STLの講義#3を参照してください。基本的にb、テンプレートパラメータを推定する参照へのバインドArgs... = { B }は、IDとして完全に一致しますが、へのバインドにB const &は、ID変換の厳密なスーパーセットである修飾子変換が必要です。

const-referenceへの明示的な変換により、テンプレート化されたコンストラクターと非テンプレートコンストラクターの両方が完全に一致するようになりましたが、非テンプレートであることはタイブレーカーです。

于 2012-08-08T23:38:52.553 に答える
2

これは、constに物事をキャストする必要なしに機能します:

#include <iostream>
struct A {
  A(){}
  A(const A &){ std::cout << "IN A" << std::endl; }
};

struct B : public A{
  B() = default;

  template<typename A0, typename ...Args,
           typename = typename std::enable_if
      <
             !std::is_same<typename std::decay<A0>::type, A>::value &&
             !std::is_same<typename std::decay<A0>::type, B>::value &&
             std::is_constructible<A, A0, Args...>::value
             >::type>
  B(A0&& a0, Args &&...args)
    : A(std::forward<A0>(a0), std::forward<Args>(args)...) {}

  B(const A &a):A(a){ std::cout << "IN B-A" << std::endl; }                                                                                
  B(const B &b):A(b){ std::cout << "IN B-B" << std::endl; }                                                                                
};

int main(){
  A a;      // 1. Prints nothing as expected                                                                                                    
  B b(a);   // 2. Prints "IN A" only                                                                                                              
  B b1(b);  // 3. Prints "IN A" only                                                                                                              
  return 0;
}

作者にとっては厄介ですが、クライアントにとってはよりクリーンです。

于 2012-08-08T23:46:01.803 に答える