15

私はC++11の新機能を試しています。私のセットアップでは、継承コンストラクターを使用したいのですが、残念ながら、まだそれらを実装しているコンパイラーはありません。したがって、私は同じ動作をシミュレートしようとしています。私はこのようなものを書くことができます:

template <class T>
class Wrapper : public T {
    public:
    template <typename... As>
    Wrapper(As && ... as) : T { std::forward<As>(as)... } { }
    // ... nice additions to T ...
};

これは機能します...ほとんどの場合。クラスを使用するコードは、WrapperSFINAEを使用して、そのようなコードをWrapper<T>構築する方法を検出する必要がある場合があります。ただし、次の問題があります。オーバーロードの解決に関する限り、のコンストラクターはWrapper<T>すべての引数を受け入れますが、それらを使用して型を構築できない場合、コンパイルは失敗します(これはSFINAEではカバーされません)。T

コンストラクターテンプレートのさまざまなインスタンス化を条件付きで有効にしようとしていましたenable_if

    template <typename... As, typename std::enable_if<std::is_constructible<T, As && ...>::value, int>::type = 0>
    Wrapper(As && ... as) // ...

次の場合に限り、正常に機能します。

  • の適切なコンストラクタTpublic
  • T抽象的ではありません

私の質問は、上記の2つの制約を取り除く方法です。

式が内で整形sizeof()式であるかどうかを(SFINAEとを使用して)チェックすることにより、最初の問題を克服しようとしました。ただし、これはもちろん機能しません。派生クラスがそのベースの保護されたコンストラクターを使用できる唯一の方法は、メンバーの初期化リストにあるためです。new T(std::declval<As &&>()...) Wrapper<T>

2つ目については、まったくわかりません。これは、Wrapperの抽象関数を実装しTて完全な型にすることがあるため、さらに必要なものです。

私は次のような解決策が必要です:

  • 標準に従って正しい
  • gcc-4.6。*、gcc-4.7。*、またはclang-3。*のいずれかで動作します

ありがとう!

4

1 に答える 1

12

これは私のローカルGCC(4.7、rubenvbの好意による)でうまく機能しているようです。ただし、ideoneのGCCは、いくつかの「実装された」コンパイラ内部エラーを出力します。

クラスの「実装の詳細」をExperiment公開する必要がありました。何らかの理由で(バグのような匂いがします)、私のバージョンのGCCは、クラス自体だけがそれを使用しているにもかかわらず、それらがプライベートであると不平を言っています。

#include <utility>

template<typename T, typename Ignored>
struct Ignore { typedef T type; };

struct EatAll {
  template<typename ...T>
  EatAll(T&&...) {}
};

template<typename T>
struct Experiment : T {
public:
  typedef char yes[1];
  typedef char no[2];

  static void check1(T const&);
  static void check1(EatAll);

  // if this SFINAE fails, T accepts it
  template<typename ...U>
  static auto check(int, U&&...u)
    -> typename Ignore<no&, 
        decltype(Experiment::check1({std::forward<U>(u)...}))>::type;

  template<typename ...U>
  static yes &check(long, U&&...);

public:
  void f() {}
  template<typename ...U, 
           typename std::enable_if<
             std::is_same<decltype(Experiment::check(0, std::declval<U>()...)),
                          yes&>::value, int>::type = 0>
  Experiment(U &&...u):T{ std::forward<U>(u)... }
  {}
};

// TEST

struct AbstractBase {
  protected:
    AbstractBase(int, float);
    virtual void f() = 0;
};

struct Annoyer { Annoyer(int); };

void x(Experiment<AbstractBase>);
void x(Annoyer);

int main() {
  x({42});
  x({42, 43.f});
}

更新:コードはClangでも機能します。

于 2012-08-22T19:36:53.620 に答える