すべての欠点を持つ仮想関数を必要としないコンパイル時のポリモーフィズム設計を作成しようとしています。ただし、基本クラスのコンテナーに派生クラスを保持する機能をシミュレートできる、シンプルで効果的で理解しやすいコンテナーの作成に苦労しています。コンパイル時の可変引数ベクトルを使用した以前の試みは機能していましたが、コードは非常に混乱していました。このソリューションは私にはきれいに思えます。基本的な CTRP を実装する単純なコードがあります。ただし、std::any
オブジェクトを格納するランタイム コンテナを作成し、オブジェクトのタイプに基づいて、実行するアクションを定義できます。いくつか質問があります。
std::any
の使用とその後any_cast<>()
の使用は、仮想関数の使用と比較してパフォーマンスをどのように妨げますか?この状況で の使用は
std::any
有効ですか?そのようなコンテナを実装するより良い方法はありますか?
仮想関数を使用して (を使用して
virtual <type> foo() = 0
) 実装を強制する方法はありますか?CRTP ハンドラーになるオブジェクトを作成するのは良い考えですか? だから私はCRTP呼び出しのための関数を持っていませんが、それらの呼び出しを管理できるオブジェクトはありますか?
ありがとうございました。
基本クラスは次のとおりです。
class base {
private:
base() = default;
friend T;
T& implementation = static_cast<T&>(*this);
public:
auto do_stuff() {
return implementation.do_stuff();
}
};
実装は次のとおりです。
#include <iostream>
class implementation_a : public base<implementation_a> {
public:
auto do_stuff() {
std::cout << 42 << std::endl;
}
};
class implementation_b : public base<implementation_b> {
public:
auto do_stuff() {
return 420;
}
};
コンテナは次のとおりです。
#include <vector>
#include <any>
class crtp_vector {
private:
std::vector<std::any> vec;
public:
auto begin() {
return vec.begin();
}
auto end() {
return vec.end();
}
auto empty() {
return vec.empty();
}
auto size() {
return vec.size();
}
void clear() {
vec.clear();
}
void push_back(const std::any& val) {
vec.push_back(val);
}
auto emplace_back(const std::any& val) {
vec.emplace_back(val);
}
};
主なものは次のとおりです。
#include "crtp_container.h"
#include <utility>
/* crtp call handler */
template <typename T>
auto crtp_call(T& val) {
return val.do_stuff();
}
int main() {
crtp_vector vec;
implementation_a A;
implementation_b B;
vec.push_back(A);
vec.push_back(B);
for(auto &member : vec) {
if(member.type().name() == typeid(implementation_a).name()) {
crtp_call(std::any_cast<implementation_a&>(member));
}
else if(member.type().name() == typeid(implementation_b).name()) {
std::cout << crtp_call(std::any_cast<implementation_b&>(member)) << std::endl;
}
else {
std::cerr << "no viable type conversion" << std::endl;
}
}
return 0;
}