2016-04-15 8 views
1

私は以下で使用しようとしている高度なテンプレートテクニックのいくつかを初めて使用しているので、用語が正しくない可能性があります。私はBoxの基本型と、Boxを継承するいくつかのクラスを持っています。私はテンプレートパラメータに基づいて特定のサブクラスのインスタンスを構築しようとしています。部分テンプレートの特殊化を使用して基底クラスを選択する

これはBox<T>タイプです。別の型に変換するには

auto box = std::shared_ptr<Box<int>>(new Box<int>());

、我々は返す:Convert機能は、私はそうのような新しいBox<int>タイプを作成することができますU.

template<typename T> 
class Box : public std::enable_shared_from_this<Box<T>> { 
public: 

    // Box<T> --> Box<U> 
    template <typename Func> 
    auto Convert(Func f) -> std::shared_ptr<Box<decltype(f(std::declval<T>()))>>; 

    virtual void Print() { 
    std::cout << "box" << std::endl; 
    } 
}; 

を入力返す関数を使用して新しいBox<U>を作成することができますタイプConvertedBoxのサブクラスです(実際には、遅延関数を遅延適用するため、これを行います)。

template<typename T, typename U, typename Func> 
class ConvertedBox : public Box<T> { 
public: 
    ConvertedBox(typename std::shared_ptr<Box<U>> box, Func func) : 
    box_(box), func_(func) 
    {} 

    virtual void Print() { 
    std::cout << "converted box" << std::endl; 
    } 

private: 
    std::shared_ptr<Box<U>> box_; 
    Func func_; 
}; 

ここでサブクラスインスタンスを作成する方法です。

// implementation of convert 
template <typename T> 
template <typename Func> 
auto Box<T>::Convert(Func f) -> std::shared_ptr<Box<decltype(f(std::declval<T>()))>> 
{ 
    using ReturnType = decltype(f(std::declval<T>())); 
    auto p = new ConvertedBox<ReturnType, T, Func>(this->shared_from_this(), f); 
    return std::shared_ptr<Box<ReturnType>>(p); 
} 

今、私は、次のような呼び出しを使用して新しいBox<U>を構築することができます:私が行うことができるようにしたいどのような

auto converted_float_box = box->Convert([](int v) -> float { 
    return (float)v; 
}); 

適用されている機能の種類に応じてBox<>基本クラスを専門とします。例えば、私はそうのようBox<std::pair<int, int>>に変換する場合:

auto converted_pair_box = box->Convert([](int v) -> std::pair<int, int> { 
    return std::make_pair(v, v); 
}); 

私はここでは例として、プリントを使用しています(Box<std::pair<K, V>>にのみ使用可能です結果に関数を呼び出すことができるようにしたいと思いますで。スペシャライゼーションは複雑です)。

converted_pair_box->PairOnlyPrint(); 

私はstd::pair<K,V>Boxを特化しようとしたが、運としました。

template<typename K, typename V> 
class PairBox : public Box<std::pair<K, V>> { 
public: 
    void PairOnlyPrint() { 
    std::cout << "only pair box" << std::endl; 
    }; 
}; 

コンパイラはまだBox<>に解決されるので、PairOnlyPrintは使用できません。これを達成する方法はありますか?

編集1:指摘したように、Convertは無料の機能ではありません。あなたのclass PairBox

+0

は 'Convert'は'ボックス '返すので、何を得ることは'ボックス ''ないPairBox'です。あなたができることは、派生クラスをテンプレート引数として基本クラスに渡すことです( 'Box ')。これは 'Convert'が実際にはフリー関数ではないと仮定していますが(例ではありません) – Aleph

+0

はい、私はそれが問題であることを知っていたと言及していたはずです。一般的に、私はこの時点で、 'Convert'関数の 'if'ステートメントのような感じにしようとしています。あなたが提案しているのはCRTPですか? –

+0

はい、提案はCRTPを利用するでしょう。また、テンプレートパラメータを 'Convert'に追加することもできます。 – Aleph

答えて

1

が専門ではない、専門は次のようになります。

template<typename K, typename V> 
class Box<std::pair<K, V>>: public std::enable_shared_from_this<Box<std::pair<K, V>>> { 
public: 

    // Box<T> --> Box<U> 
    template <typename Func> 
    auto Convert(Func f) 
    -> std::shared_ptr<Box<decltype(f(std::declval<std::pair<K, V>>()))>>; 

    virtual void Print() { std::cout << "pair box" << std::endl; } 
    void PairOnlyPrint() { std::cout << "only pair box" << std::endl; }; 
}; 
+0

これは私の最初のハードルを越えてくれましたので、印刷ステートメントが正しく機能しています。私はBoxに追加した汎用インターフェースに気づいた私はstd :: pairの専門分野で複製する必要があります。これを達成する方法はありますか? –

+0

いくつかの関連する質問を見て、この継承プロパティを使用したテンプレートの特殊化が可能であるようです。私の例で何が間違っているか分かりません。 –

関連する問題