私は以下で使用しようとしている高度なテンプレートテクニックのいくつかを初めて使用しているので、用語が正しくない可能性があります。私は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
は 'Convert'は'ボックス '返すので、何を得ることは'ボックス ''ないPairBox'です。あなたができることは、派生クラスをテンプレート引数として基本クラスに渡すことです( 'Box ')。これは 'Convert'が実際にはフリー関数ではないと仮定していますが(例ではありません) –
Aleph
はい、私はそれが問題であることを知っていたと言及していたはずです。一般的に、私はこの時点で、 'Convert'関数の 'if'ステートメントのような感じにしようとしています。あなたが提案しているのはCRTPですか? –
はい、提案はCRTPを利用するでしょう。また、テンプレートパラメータを 'Convert'に追加することもできます。 – Aleph